<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="generator" content="HTML Tidy for HTML5 for Linux version 5.6.0">
<link rel="stylesheet" type="text/css" href="style.css">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TACACS+</title>
<meta name="GENERATOR" content="Modular DocBook HTML Stylesheet Version 1.79">
</head>
<body class="article" bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="ARTICLE">
<div class="TITLEPAGE">
<h1 class="title"><a name="AEN2" id="AEN2">TACACS+</a></h1>
<h3 class="author"><a name="AEN4" id="AEN4">Marc Huber</a></h3>
<span class="releaseinfo">$Id: 36c11059239f9f2e5b39ecfd3a5e39e3d7a28581 $<br></span>
<hr></div>
<div class="TOC">
<dl>
<dt><b>Table of Contents</b></dt>
<dt>1. <a class="lk" href="#AEN9">Introduction</a></dt>
<dd>
<dl>
<dt>1.1. <a class="lk" href="#AEN39">Download</a></dt>
</dl>
</dd>
<dt>2. <a class="lk" href="#AEN44">Definitions and Terms</a></dt>
<dd>
<dl>
<dt>2.1. <a class="lk" href="#AEN74">TACACS, XTACACS and TACACS+</a></dt>
</dl>
</dd>
<dt>3. <a class="lk" href="#AEN91">Operation</a></dt>
<dd>
<dl>
<dt>3.1. <a class="lk" href="#AEN105">Command line syntax</a></dt>
<dt>3.2. <a class="lk" href="#AEN126">Signals</a></dt>
<dt>3.3. <a class="lk" href="#AEN141">Event mechanism selection</a></dt>
<dt>3.4. <a class="lk" href="#AEN167">Sample Configuration</a></dt>
<dt>3.5. <a class="lk" href="#AEN179">Sample Configuration with Realms</a></dt>
</dl>
</dd>
<dt>4. <a class="lk" href="#AEN183">Configuration Syntax</a></dt>
<dd>
<dl>
<dt>4.1. <a class="lk" href="#AEN227">Global options</a></dt>
<dd>
<dl>
<dt>4.1.1. <a class="lk" href="#AEN233">Limits and timeouts</a></dt>
<dt>4.1.2. <a class="lk" href="#AEN260">DNS</a></dt>
<dt>4.1.3. <a class="lk" href="#AEN292">Process-specific options</a></dt>
<dt>4.1.4. <a class="lk" href="#AEN326">Railroad Diagrams</a></dt>
</dl>
</dd>
<dt>4.2. <a class="lk" href="#AEN335">Realms</a></dt>
<dd>
<dl>
<dt>4.2.1. <a class="lk" href="#AEN383">Railroad Diagrams</a></dt>
</dl>
</dd>
<dt>4.3. <a class="lk" href="#AEN392">Realm options</a></dt>
<dd>
<dl>
<dt>4.3.1. <a class="lk" href="#AEN397">Logging</a></dt>
<dt>4.3.2. <a class="lk" href="#AEN539">Limits and timeouts</a></dt>
<dt>4.3.3. <a class="lk" href="#AEN827">Hosts</a></dt>
<dt>4.3.4. <a class="lk" href="#AEN1335">Time Ranges</a></dt>
<dt>4.3.5. <a class="lk" href="#AEN1361">Access Control Lists</a></dt>
<dt>4.3.6. <a class="lk" href="#AEN1436">Rewriting User Names</a></dt>
<dt>4.3.7. <a class="lk" href="#AEN1446">Scripts</a></dt>
<dt>4.3.8. <a class="lk" href="#AEN1498">Users and Groups</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt>5. <a class="lk" href="#AEN2386">MAVIS Backends</a></dt>
<dd>
<dl>
<dt>5.1. <a class="lk" href="#AEN2394">LDAP Backends</a></dt>
<dd>
<dl>
<dt>5.1.1. <a class="lk" href="#AEN2559">LDAP Custom Schema Backend</a></dt>
<dt>5.1.2. <a class="lk" href="#AEN2582">Active Directory Backend</a></dt>
<dt>5.1.3. <a class="lk" href="#AEN2588">Generic LDAP Backend</a></dt>
</dl>
</dd>
<dt>5.2. <a class="lk" href="#AEN2596">PAM backend</a></dt>
<dt>5.3. <a class="lk" href="#AEN2601">System Password Backends</a></dt>
<dt>5.4. <a class="lk" href="#AEN2609">Shadow Backend</a></dt>
<dt>5.5. <a class="lk" href="#AEN2632">RADIUS Backends</a></dt>
<dd>
<dl>
<dt>5.5.1. <a class="lk" href="#AEN2663">Sample Configuration</a></dt>
</dl>
</dd>
<dt>5.6. <a class="lk" href="#AEN2666">Experimental Backends</a></dt>
<dt>5.7. <a class="lk" href="#AEN2670">Error Handling</a></dt>
</dl>
</dd>
<dt>6. <a class="lk" href="#AEN2678">Debugging</a></dt>
<dd>
<dl>
<dt>6.1. <a class="lk" href="#AEN2681">Debugging Configuration Files</a></dt>
<dt>6.2. <a class="lk" href="#AEN2689">Trace Options</a></dt>
</dl>
</dd>
<dt>7. <a class="lk" href="#AEN2847">Frequently Asked Questions</a></dt>
<dt>8. <a class="lk" href="#AEN3093">Canned Configurations</a></dt>
<dd>
<dl>
<dt>8.1. <a class="lk" href="#AEN3096">Login Authentication</a></dt>
<dt>8.2. <a class="lk" href="#AEN3107">Command Authorization</a></dt>
<dt>8.3. <a class="lk" href="#AEN3121">Network Access Authorization</a></dt>
<dt>8.4. <a class="lk" href="#AEN3134">ARAP</a></dt>
<dt>8.5. <a class="lk" href="#AEN3142">Callback</a></dt>
</dl>
</dd>
<dt>9. <a class="lk" href="#AEN3156">Authorization AV pairs</a></dt>
<dt>10. <a class="lk" href="#AEN3571">Upgrading from Previous Releases</a></dt>
<dt>11. <a class="lk" href="#AEN3587">Bugs</a></dt>
<dt>12. <a class="lk" href="#AEN3601">References</a></dt>
<dt>13. <a class="lk" href="#AEN3611">Copyrights and Acknowledgements</a></dt>
</dl>
</div>
<div class="section">
<h2 class="section"><a name="AEN9" id="AEN9">1. Introduction</a></h2>
<p><span class="bold"><b class="emphasis">tac_plus</b></span> is a TACACS+ daemon. It provides Cisco Systems routers and access servers with authentication, authorisation and accounting services.</p>
<p>This version is a major rewrite of the original Cisco source code. However, it's outdated and unsupported. Feel encouraged to use <a class="lk" href="https://projects.pro-bono-publico.de/event-driven-servers/doc/tac_plus-ng.html" target="_top">tac_plus-ng</a>.</p>
<p>Key features include:</p>
<ul>
<li>
<p>NAS specific host keys, prompts, enable passwords</p>
</li>
<li>
<p>NAS- and ACL-dependent group memberships</p>
</li>
<li>
<p>Flexible external backends for user profiles (e.g. via PERL scripts or C; LDAP (including ActiveDirectory), RADIUS and others are included)</p>
</li>
<li>
<p>Connection multiplexing (multiple concurrent NAS clients per process)</p>
</li>
<li>
<p>Session multiplexing (multiple concurrent sessions per connection, <span class="emphasis"><i class="emphasis">single-connection</i></span>)</p>
</li>
<li>
<p>Scalable, no limit on users, clients or servers.</p>
</li>
<li>
<p>CLI context aware. At the time of writing this, no other TACACS+ daemon is.</p>
</li>
<li>
<p>Both IPv4 and IPv6 are fully supported.</p>
</li>
<li>
<p>Implements and autodetects <a class="lk" href="https://www.haproxy.org/" target="_top">HAProxy</a> protocol 2.</p>
</li>
<li>
<p>Compliant to the original TACACS+ protocol specification (draft 1.78).</p>
</li>
</ul>
<div class="section">
<hr>
<h3 class="section"><a name="AEN39" id="AEN39">1.1. Download</a></h3>
<p>You can download the source code from the GitHub repository at <a class="lk" href="https://github.com/MarcJHuber/event-driven-servers/" target="_top">https://github.com/MarcJHuber/event-driven-servers/</a>. On-line documentation is available via <a class="lk" href="https://projects.pro-bono-publico.de/event-driven-servers/doc/" target="_top">https://projects.pro-bono-publico.de/event-driven-servers/doc/</a>, too.</p>
</div>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN44" id="AEN44">2. Definitions and Terms</a></h2>
<p>The following chapters utilize a couple of terms that may need further explanation:</p>
<div class="informaltable"><a name="AEN47" id="AEN47"></a>
<table border="1" class="CALSTABLE">
<col width="20%" title="col1">
<col width="80%" title="col2">
<tbody>
<tr>
<td>NAC</td>
<td>A Network Access Client, e.g. the source host of a <tt class="literal">telnet</tt> connection.</td>
</tr>
<tr>
<td>NAS</td>
<td>A Network Access Server, e.g. a Cisco box, or any other client which makes TACACS+ authentication and authorization requests, or generates TACACS+ accounting packets.</td>
</tr>
<tr>
<td>Daemon</td>
<td>A program which services network requests for authentication and authorization, verifies identities, grants or denies authorizations, and logs accounting records.</td>
</tr>
<tr>
<td>AV pairs</td>
<td>Strings of text in the form <tt class="literal">attribute=value</tt>, sent between a NAS and a TACACS+ daemon as part of the TACACS+ protocol.</td>
</tr>
</tbody>
</table>
</div>
<p>Since a <span class="emphasis"><i class="emphasis">NAS</i></span> is sometimes referred to as a <span class="emphasis"><i class="emphasis">server</i></span>, and a <span class="emphasis"><i class="emphasis">daemon</i></span> is also often referred to as a <span class="emphasis"><i class="emphasis">server</i></span>, the term <span class="emphasis"><i class="emphasis">server</i></span> has been avoided here in favor of the less ambiguous terms <span class="emphasis"><i class="emphasis">NAS</i></span> and <span class="emphasis"><i class="emphasis">Daemon</i></span>.</p>
<div class="section">
<hr>
<h3 class="section"><a name="AEN74" id="AEN74">2.1. TACACS, XTACACS and TACACS+</a></h3>
<p>As a tidbit of historical value, there are about three versions of authentication protocol that people may refer to as <span class="emphasis"><i class="emphasis">TACACS</i></span>:</p>
<p>The first is ordinary <span class="emphasis"><i class="emphasis">TACACS</i></span>, which was the first one offered on Cisco boxes and has been in use for many years. The second is an extension to the first, commonly called <span class="emphasis"><i class="emphasis">Extended TACACS</i></span> or <span class="emphasis"><i class="emphasis">XTACACS</i></span>, introduced in 1990. Both are UDP based services.</p>
<p>The third one, and that's the version virtually everybody uses right now, is <span class="emphasis"><i class="emphasis">TACACS+</i></span> or <span class="emphasis"><i class="emphasis">tac_plus</i></span>, which is what is documented here. <span class="emphasis"><i class="emphasis">TACACS+</i></span> is based on TCP and as such <span class="bold"><b class="emphasis">not compatible</b></span> with any previous versions of <span class="emphasis"><i class="emphasis">TACACS</i></span>.</p>
<p>Apparently, at least one vendor did implement <span class="emphasis"><i class="emphasis">TACACS+</i></span>, but refers to it as <span class="emphasis"><i class="emphasis">HWTACACS</i></span>. Chances are that there are no technical (but possibly marketing or legal) reasons behind that. Documentation is scarce.</p>
</div>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN91" id="AEN91">3. Operation</a></h2>
<p>This section gives a brief and basic overview on how to run <span class="bold"><b class="emphasis">tac_plus</b></span>.</p>
<p>In earlier versions, <span class="bold"><b class="emphasis">tac_plus</b></span> wasn't a standalone program but had to be invoked by <span class="bold"><b class="emphasis">spawnd</b></span>. This has changed, as <span class="bold"><b class="emphasis">spawnd</b></span> functionality is now part of the <span class="bold"><b class="emphasis">tac_plus</b></span> binary. However, using a dedicated <span class="bold"><b class="emphasis">spawnd</b></span> process is still possible and, more importantly, the <span class="bold"><b class="emphasis">spawnd</b></span> configuration options and documentation remain valid.</p>
<p><span class="bold"><b class="emphasis">tac_plus</b></span> may use auxiliary <span class="bold"><b class="emphasis">MAVIS</b></span> backend modules for authentication and authorization.</p>
<div class="section">
<hr>
<h3 class="section"><a name="AEN105" id="AEN105">3.1. Command line syntax</a></h3>
<p>The only mandatory argument is the path to the configuration file:</p>
<pre class="screen">tac_plus [ <span class="emphasis"><i class="emphasis">-P</i></span> ] [ <span class="emphasis"><i class="emphasis">-d level</i></span> ] [ <span class="emphasis"><i class="emphasis">-i child_id</i></span> ] <span class="emphasis"><i class="emphasis">configuration-file</i></span> [ <span class="emphasis"><i class="emphasis">id</i></span> ]</pre>
<p>If the program was compiled with CURL support, <span class="emphasis"><i class="emphasis">configuration-file</i></span> may be an URL.</p>
<p>Keep the <tt class="literal">-P</tt> option in mind - it is imperative that the configuration file supplied is syntactically correct, as the daemon won't start if there are any parsing errors at start-up.</p>
<p>The <tt class="literal">-d</tt> switch enables debugging. You most likely don't want to use this. Read the source if you need to.</p>
<p>The <tt class="literal">-i</tt> option is only honoured if the build-in <span class="bold"><b class="emphasis">spawnd</b></span> functionality is used. In that case, it selects the configuration ID for <span class="bold"><b class="emphasis">tac_plus</b></span>, while the optional last argument <span class="emphasis"><i class="emphasis">id</i></span> sets the ID of the <span class="bold"><b class="emphasis">spawnd</b></span> configuration section.</p>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN126" id="AEN126">3.2. Signals</a></h3>
<p>Both the master (that's the process running the <span class="bold"><b class="emphasis">spawnd</b></span> code) and the child processes (running the <span class="bold"><b class="emphasis">tac_plus</b></span> code) intercept the <tt class="literal">SIGHUP</tt> signal:</p>
<ul>
<li>
<p>The master process will restart upon reception of <tt class="literal">SIGHUP</tt>, re-reading the configuration file. The child processes will recognize that the master process is no longer available. It will continue to serve the existing connections and terminate when idle.</p>
</li>
<li>
<p>If <tt class="literal">SIGHUP</tt> is sent to a child process it will stop accepting new connections from its master process. It will continue to serve the existing connections and terminate when idle.</p>
</li>
</ul>
<p>Sending <tt class="literal">SIGUSR1</tt> to the master process will cause it to abandon existing child processes (these will continue to serve the existing connections only) and start new child processes.</p>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN141" id="AEN141">3.3. Event mechanism selection</a></h3>
<p>Several level-triggered event mechanisms are supported. By default, the one best suited for your operating system will be used. However, you may set the environment variable <tt class="literal">IO_POLL_MECHANISM</tt> to select a specific one.</p>
<p>The following event mechanisms are supported (in order of preference):</p>
<ul>
<li>
<p>port (Sun Solaris 10 and higher only, <tt class="literal">IO_POLL_MECHANISM=32</tt>)</p>
</li>
<li>
<p>kqueue (*BSD and Darwin only, <tt class="literal">IO_POLL_MECHANISM=1</tt>)</p>
</li>
<li>
<p>/dev/poll (Sun Solaris only, <tt class="literal">IO_POLL_MECHANISM=2</tt>)</p>
</li>
<li>
<p>epoll (Linux only, <tt class="literal">IO_POLL_MECHANISM=4</tt>)</p>
</li>
<li>
<p>poll (<tt class="literal">IO_POLL_MECHANISM=8</tt>)</p>
</li>
<li>
<p>select (<tt class="literal">IO_POLL_MECHANISM=16</tt>)</p>
</li>
</ul>
<p>Environment variables can be set in the configuration file at top-level:</p>
<pre class="screen">setenv IO_POLL_MECHANISM = 4</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN167" id="AEN167">3.4. Sample Configuration</a></h3>
<p>A single configuration file is sufficient for configuring <span class="bold"><b class="emphasis">spawnd</b></span>, <span class="bold"><b class="emphasis">tac_plus</b></span> and the <span class="emphasis"><i class="emphasis">MAVIS</i></span> authentication and authorization backends.</p>
<p>The following <span class="bold"><b class="emphasis">spawnd</b></span> configuration stanza accepts connections on TCP ports 49 and 4949 and forwards these to one of the <span class="bold"><b class="emphasis">tac_plus</b></span> processes. The <span class="bold"><b class="emphasis">tac_plus</b></span> configuration configures a couple of user groups, has one single user defined and relies on the <span class="emphasis"><i class="emphasis">MAVIS</i></span> backend for additional users.</p>
<pre class="screen">#!/usr/local/sbin/tac_plus
id = spawnd {
    listen = { port = 49 }
    listen = { port = 4949 }
    #
    # See the spawnd configuration guide for further configuration options.
}

id = tac_plus {
    accounting log = /var/log/tac_plus/%Y/%m/%d.log
    retire limit = 1000
    mavis module = external {
        exec = /usr/local/lib/mavis_tacplus_passwd.pl
        # see the MAVIS configuration manual for more options and other modules
    }
    login backend = mavis

    host = world {
        welcome banner = "\nHitherto shalt thou come, but no further. (Job 38.11)\n\n"
        key = QaWsEdRfTgY
        enable 15 = clear test
        address = 0.0.0.0/0
    }

    group = readwrite {
        default service = permit
        service = shell {
            default command = permit
            set priv-lvl = 15
        }
    }

    group = getconfig {
        default service = permit
        service = shell {
            set autocmd = "sho run"
            set priv-lvl = 15
        }
    }

    user = marc {
       login = crypt $1$xxxxxxxx$hDZPHghXe8XvoHeFdqUwm/
       member = readwrite@world
       member = getconfig@192.168.0.0/16
    }
}</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN179" id="AEN179">3.5. Sample Configuration with Realms</a></h3>
<p>Here's a more sophisticated example, acknowledging that most folks prefer to look at sample configurations instead of actually reading documentation.</p>
<pre class="screen">
syslog default = deny

id = spawnd {
  # Really, have a look at the spawnd configuration. There are
  # lots of useful options.

  listen = {
    port = 4949
  }

  listen = {
    port = 4950 realm = core
  }
}

id = tac_plus {
  client realm = adminRealm     # Could specify these
  aaa realm = local             # at host level, too.
  dns reverse-lookup = no

  realm = adminRealm {
    host = myPCs {
      address = 192.0.2.8,192.0.2.24/29
    }
  }

  realm = customerRealm {
    dns reverse-lookup = yes
    host = customer {
      address = 172.16.0.0/12
    }
  }

  # This will be placed in the "default" realm
  host = cpeRouters {
    address = 0.0.0.0/0
    key = myKey
    welcome banner = "Welcome C=%%C Time=%c\n"
    client realm = customerRealm
    aaa realm = ldapRealm
  }

  # And this one in the "core" realm. Could write this as
  # realm = ... { host = ... }, too.
  host realm core = coreRouters {
    address = 0.0.0.0/0
    key = CoreKey
    client realm = adminRealm
    aaa realm = unixRealm
  }

  realm = unixRealm {
    mavis module = groups {
      resolve gids = yes
      groups filter = /^(guest|staff)$/
      script out = {
        # copy the already filtered UNIX group access list to TACMEMBER
        eval $GIDS =~ /^(.*)$/
        set $TACMEMBER = $1
      }
    }

    mavis module = external {
      exec = /usr/local/sbin/pammavis "pammavis" "-s" "mavis"
    }

    user backend = mavis
    login backend = mavis chpass

    group = staff {
      service = shell {
        set priv-lvl = 15
        script = {
          if (cmd == "") permit # shell startup
          if (cmd =~ /^configure/) permit
        }
        message debug = "author '%c %a'"
        cmd = show { permit .* }
      }
    }

    group = guest {
      member = staff
      service = shell {
        cmd = show { permit .* }
        message deny = "denied by t+"
      }
    }
  }

  realm = ldapRealm {
    mavis module = external {
      exec = /usr/local/lib/mavis/mavis_tacplus_ads.pl
      setenv USE_TLS = 0
      setenv LDAP_HOSTS = "192.0.2.193"
      setenv LDAP_SCOPE = sub
      setenv LDAP_BASE = "dc=example,dc=com"
    }
    user backend = mavis
    login backend = mavis
    pap backend = mavis
  }

  realm = localRealm {
    user = marc {
      password = clear marc
      service = shell {
        default command = permit
      }
    }
  } 
}</pre></div>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN183" id="AEN183">4. Configuration Syntax</a></h2>
<p>The configuration stanzas covered by the following sections are to be placed between</p>
<pre class="screen">id = tac_plus = {</pre>
<p>and the corresponding</p>
<pre class="screen">}</pre>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Comments in Configuration Files</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>Comments can appear anywhere in the configuration file, starting with the <tt class="literal">#</tt> character and extending to the end of the current line. Should you need to disable this special meaning of the <tt class="literal">#</tt> character, e.g. if you have a password containing a <tt class="literal">#</tt> character, simply enclose the string containing it within double quotes.</p>
</td>
</tr>
</table>
</div>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Including Files</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>Configuration files may refer to other configuration files:</p>
<p><tt class="literal">include =</tt> <span class="emphasis"><i class="emphasis">file</i></span></p>
<p>will read and parse <span class="emphasis"><i class="emphasis">file</i></span>. Shell wildcard patterns are expanded by <tt class="literal">glob</tt><span class="emphasis"><i class="emphasis">(3)</i></span>. The <tt class="literal">include</tt> statement will be accepted virtually everywhere (but not in comments or textual strings).</p>
</td>
</tr>
</table>
</div>
<p>The recommended order for writing a configuration file is</p>
<ol type="1">
<li>
<p>global definitions</p>
</li>
<li>
<p>hosts</p>
</li>
<li>
<p>timespecs</p>
</li>
<li>
<p>acls</p>
</li>
<li>
<p>groups</p>
</li>
<li>
<p>users</p>
</li>
</ol>
The reasoning behind that non-random order is that parts of the configuration may use other parts, and these need to exist before being used.
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/TacplusConfig.svg"></p>
<div class="caption">
<p>Railroad diagram: TacPlusConfig</p>
</div>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN227" id="AEN227">4.1. Global options</a></h3>
<p>The global configuration section may contain the following configuration directives, plus the <span class="emphasis"><i class="emphasis">realm</i></span> options detailed in the next section. <span class="emphasis"><i class="emphasis">realm</i></span> options defined at global level will implicitely be assigned to the <span class="emphasis"><i class="emphasis">default</i></span> realm and will be inherited to subsequently defined realms.</p>
<div class="section">
<hr>
<h4 class="section"><a name="AEN233" id="AEN233">4.1.1. Limits and timeouts</a></h4>
<p>A number of global limits and timeouts may be specified exclusively at global level:</p>
<ul>
<li>
<p><tt class="literal">retire limit =</tt> <span class="emphasis"><i class="emphasis">n</i></span></p>
<p>The particular daemon instance will terminate after processing <span class="emphasis"><i class="emphasis">n</i></span> requests. The <span class="bold"><b class="emphasis">spawnd</b></span> instance will spawn a new instance if necessary.</p>
<p>Default: unset</p>
</li>
<li>
<p><tt class="literal">retire timeout =</tt> <span class="emphasis"><i class="emphasis">s</i></span></p>
<p>The particular daemon instance will terminate after <span class="emphasis"><i class="emphasis">s</i></span> seconds. <span class="bold"><b class="emphasis">spawnd</b></span> will spawn a new instance if necessary.</p>
<p>Default: unset</p>
</li>
</ul>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Time units</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>Appending <tt class="literal">s</tt>, <tt class="literal">m</tt>, <tt class="literal">h</tt> or <tt class="literal">d</tt> to any timeout value will scale the value as expected.</p>
</td>
</tr>
</table>
</div>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN260" id="AEN260">4.1.2. DNS</a></h4>
<p><span class="bold"><b class="emphasis">tac_plus</b></span> can make use of static and, if compiled with <a class="lk" href="https://c-ares.org/" target="_top">c-ares</a> support, of dynamic DNS entries. The relevant global configuration options at global level are:</p>
<ul>
<li>
<p><tt class="literal">dns cleanup period =</tt> <span class="emphasis"><i class="emphasis">s</i></span></p>
<p>Remove unused dynamic DNS data from cache after <span class="emphasis"><i class="emphasis">s</i></span> seconds. (Default: 8 hours.)</p>
</li>
<li>
<p><tt class="literal">dns preload address</tt> <span class="emphasis"><i class="emphasis">address</i></span> <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">hostname</i></span></p>
<p>Preload DNS cache with <span class="emphasis"><i class="emphasis">address</i></span>-to-<span class="emphasis"><i class="emphasis">hostname</i></span> mapping.</p>
</li>
<li>
<p><tt class="literal">dns preload file =</tt> <span class="emphasis"><i class="emphasis">filename</i></span></p>
<p>Preload DNS cache with <span class="emphasis"><i class="emphasis">address</i></span>-to-<span class="emphasis"><i class="emphasis">hostname</i></span> mappings from <span class="emphasis"><i class="emphasis">filename</i></span> (see your <tt class="literal">hosts</tt>(5) manpage for syntax).</p>
<p>Example:</p>
<pre class="screen">dns preload address 1.2.3.4 = router.example.com
dns preload file = /etc/hosts

host = router.example.com {
    # "address = 1.2.3.4" is actually implied
    key = mykey
}</pre></li>
</ul>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN292" id="AEN292">4.1.3. Process-specific options</a></h4>
<p>There are a couple of process-specific options available:</p>
<ul>
<li>
<p><tt class="literal">userid =</tt> <span class="emphasis"><i class="emphasis">uid</i></span></p>
<p>Run daemon under user id <span class="emphasis"><i class="emphasis">uid</i></span>. This option is deprecated.</p>
</li>
<li>
<p><tt class="literal">groupid =</tt> <span class="emphasis"><i class="emphasis">gid</i></span></p>
<p>Run daemon under group id <span class="emphasis"><i class="emphasis">gid</i></span>. This option is deprecated.</p>
</li>
<li>
<p><tt class="literal">working directory =</tt> <span class="emphasis"><i class="emphasis">directory</i></span></p>
<p>Changes the current working directory to <span class="emphasis"><i class="emphasis">directory</i></span>.</p>
</li>
<li>
<p><tt class="literal">coredump directory =</tt> <span class="emphasis"><i class="emphasis">directory</i></span></p>
<p>Dump cores to <span class="emphasis"><i class="emphasis">directory</i></span>. You really shouldn't need this.</p>
</li>
<li>
<p><tt class="literal">accept haproxy =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>Enables HAProxy support. Disabled by default.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN326" id="AEN326">4.1.4. Railroad Diagrams</a></h4>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/GlobalDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: GlobalDecl</p>
</div>
</div>
</div>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN335" id="AEN335">4.2. Realms</a></h3>
<p>Historically, <span class="emphasis"><i class="emphasis">realms</i></span> were introduced in listen directives in the <span class="bold"><b class="emphasis">spawnd</b></span> configuration section:</p>
<pre class="screen">spawnd = {
  listen = { port = 49 }
  listen = { port = 3939 }
  listen = { port = 4949 realm = oneRealm}
  listen = { port = 5959 realm = otherRealm}
}</pre>
<div class="tip">
<table class="tip" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/tip.svg" hspace="5" alt="Tip"></td>
<th align="left" valign="middle"><b>Default Realm</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>If <tt class="literal">spawnd</tt> doesn't supply a realm name, then <span class="emphasis"><i class="emphasis">tac_plus</i></span> will fall back to using the realm named <tt class="literal">default</tt>, which contains all the realm specific directives not defined in realm context.</p>
<p>You can select the actual default realm with</p>
<pre class="screen">default realm = <span class="emphasis"><i class="emphasis">RealmName</i></span></pre>
<p>at global configuration level.</p>
</td>
</tr>
</table>
</div>
<p>The main task of the <span class="bold"><b class="emphasis">spawnd</b></span> component is to accept a connection and forward it, including the associated realm, to the <span class="bold"><b class="emphasis">tac_plus</b></span> process. <span class="bold"><b class="emphasis">tac_plus</b></span> then uses that realm to assign the correct host object hierarchy to the connection.</p>
<p>The prefered syntax to use (and define) realms is</p>
<pre class="screen">realm = <span class="emphasis"><i class="emphasis">realmName</i></span> { ... }</pre>
<p>at global configuration level. Realms may include hosts, users, groups, <span class="emphasis"><i class="emphasis">MAVIS</i></span> configurations and various other configuration options. Realms and hosts may refer to other realms for authentication.</p>
<p>More precisely, the three uses for realms are:</p>
<ul>
<li>
<p>Authentication, Authorization and Accounting Realms</p>
<p>Everything related to users and user groups, including logging, is configured in an AAA realm. The AAA realm to use may be selected at global, realm and host level, using the</p>
<pre class="screen">aaa realm = <span class="emphasis"><i class="emphasis">realmName</i></span></pre>
<p>directive.</p>
</li>
</ul>
<ul>
<li>
<p>Network Access Server Realms</p>
<p>This is the realm where the NAS host object was defined. Hosts and NAS specific parameters are defined in this realms context.</p>
</li>
</ul>
<ul>
<li>
<p>Network Acccess Client Realms</p>
<p>NAC specific parameters may be retrieved from a NAC realm, which may be spefified at global, realm and host level:</p>
<pre class="screen">nac realm = <span class="emphasis"><i class="emphasis">realmName</i></span></pre>
<p>This may for example be used to enable DNS reverse lookups for remote clients on a per-realm basis.</p>
</li>
</ul>
<p>Defining realms is optional. As mentioned before, realm options defined at top-level will be assigned to the <tt class="literal">default</tt> realm, which is actually the default for both the <tt class="literal">aaa</tt> and <tt class="literal">nac</tt> realms.</p>
<div class="section">
<hr>
<h4 class="section"><a name="AEN383" id="AEN383">4.2.1. Railroad Diagrams</a></h4>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/RealmDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: RealmDecl</p>
</div>
</div>
</div>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN392" id="AEN392">4.3. Realm options</a></h3>
<p>The following options may be specified at <span class="emphasis"><i class="emphasis">realm</i></span> and <span class="emphasis"><i class="emphasis">global</i></span> level:</p>
<div class="section">
<hr>
<h4 class="section"><a name="AEN397" id="AEN397">4.3.1. Logging</a></h4>
<p>The software provides logs for</p>
<ul>
<li>
<p>Authentication</p>
<pre class="screen">  authentication log = <span class="emphasis"><i class="emphasis">log_destination</i></span></pre></li>
<li>
<p>Authorization</p>
<pre class="screen">  authorization log = <span class="emphasis"><i class="emphasis">log_destination</i></span></pre></li>
<li>
<p>Accounting</p>
<pre class="screen">  accounting log = <span class="emphasis"><i class="emphasis">log_destination</i></span></pre></li>
</ul>
<p>Logs may be written to multiple destinations:</p>
<pre class="screen">  authentication log = <span class="emphasis"><i class="emphasis">log_1</i></span>
  authentication log = <span class="emphasis"><i class="emphasis">log_2
...</i></span>
  authentication log = <span class="emphasis"><i class="emphasis">log_n</i></span></pre>
<p>Valid log destinations are:</p>
<ul>
<li>
<p>Files</p>
<p>For logging to plain disk files <tt class="literal">fcntl</tt><span class="emphasis"><i class="emphasis">(2)</i></span> file locking is used, so it is recommended that file resides on a local filesystem. Although <tt class="literal">fcntl</tt> locking over NFS is supported on some Unix implementations, it is notoriously unreliable, and eVen if your implementation is reliable, locking is likely to be extremely inefficient over NFS.</p>
<p>If the underlying file system supports atomic appends, <tt class="literal">fcntl</tt><span class="emphasis"><i class="emphasis">(2)</i></span> file locking may not be necessary. Prepending the log destination with a <tt class="literal">&gt;</tt> character will turn file locking off and switch log file handling to synchronous mode.</p>
<pre class="screen">  # async
  authentication log = /var/log/tac_plus/access1.log
  # sync:
  authentication log = "&gt;/var/log/tac_plus/access2.log"</pre></li>
<li>
<p>Commands</p>
<p>If the log destination starts with a <tt class="literal">|</tt> character a shell running the remainder of the destination argument will be invoked, and log messages will be feeded to that shell on standard input. Example:</p>
<pre class="screen">  authentication log = "|exec /usr/bin/logger"</pre>
<p>(The <tt class="literal">exec</tt> isn't strictly necessary here, but avoids keeping an otherwise idle shell process around.)</p>
</li>
<li>
<p>Syslog</p>
<p>Logging to <tt class="literal">syslogd</tt><span class="emphasis"><i class="emphasis">(8)</i></span> can be enabled by either using the <tt class="literal">syslog</tt> keyword</p>
<pre class="screen">  accounting log = syslog</pre>
<p>(which will use your systems <tt class="literal">syslog(3)</tt> function for logging, or by utilizing</p>
<pre class="screen">  accounting log = <span class="emphasis"><i class="emphasis">Address[:UDPPort]</i></span></pre>
<p>syntax.</p>
</li>
</ul>
<p>Moreover, named log destinations may be used, e.g.:</p>
<pre class="screen">  log = mylog {
    destination = 169.254.0.23 # UDP syslog
    # or one of the following:
    # destination = [fe80::123:4567:89ab:cdef]:514 # IPv6 UDP, with non-standard UDP port
    # destination = "/tmp/x.log" # plain file
    # destination = "&gt;/tmp/x.log" # plain file
    # destination = "|my_script.sh" # script
    # destination = syslog # syslog(3)
    #
    syslog compliance = RFC3164 # this is the default for UDP syslog
    # syslog compliance = RFC5424 # this loosely matches the new syslog standard
    syslog facility = MAIL # sets log facility
    syslog severity = DEBUG # sets log severity
    log separator = "|" # The actual default for syslog, for others it's "\t"
  }
  authentication log = mylog
  accounting log = mylog
  authorization log = mylog</pre>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Syslog</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>Logging to <tt class="literal">syslogd</tt><span class="emphasis"><i class="emphasis">(8)</i></span> can be disabled using</p>
<pre class="screen">syslog default = deny</pre></td>
</tr>
</table>
</div>
<p>Log destinations may contain <tt class="literal">strftime(3)</tt>-style character sequences, e.g.:</p>
<pre class="screen">  authorization log = /var/log/tac_plus/%Y/%m/%d.auth</pre>
<p>to automate time-based log file switching. By default, the daemon will use your local time zone for time conversion. You can switch to a different one by using the <tt class="literal">time zone</tt> option (see below).</p>
<p>There are a couple of other configuration options that may be useful:</p>
<ul>
<li>
<p><tt class="literal">date format =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>This defines a format string for date (and time) representation in subsequentially defined log files. Default:</p>
<pre class="screen">date format = "%Y-%m-%d %H:%M:%S %z"</pre></li>
<li>
<p><tt class="literal">log separator =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>This defines the CSV separator string for log entries in subsequentially defined log files. Default:</p>
<pre class="screen">log separator = "\t"</pre></li>
<li>
<p><tt class="literal">time zone =</tt> <span class="emphasis"><i class="emphasis">time-zone</i></span></p>
<p>By default, the daemon uses your local system time zone to convert the internal system time to calendar time. This option sets the <tt class="literal">TZ</tt> environment variable to the <span class="emphasis"><i class="emphasis">time-zone</i></span> argument. See your local <tt class="literal">tzset</tt> man page for details.</p>
</li>
<li>
<p><tt class="literal">umask =</tt> <span class="emphasis"><i class="emphasis">mode</i></span></p>
<p>This sets the file creation mode mask. Example:</p>
<pre class="screen">umask = 0640</pre></li>
<li>
<p><tt class="literal">authorization log group =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>Set this to have the name of the last matching group appended to the username in authorization logs (separated by a single '/' character).</p>
</li>
</ul>
<div class="section">
<hr>
<h5 class="section"><a name="AEN497" id="AEN497">4.3.1.1. Accounting</a></h5>
<p>All accounting records are written, as text, to the file (or command) specified with the <tt class="literal">accounting log</tt> directive.</p>
<p>Accounting records are text lines containing tab-separated fields. The first 6 fields are always the same. These are:</p>
<ul>
<li>
<p>timestamp</p>
</li>
<li>
<p>NAS address</p>
</li>
<li>
<p>username</p>
</li>
<li>
<p>port</p>
</li>
<li>
<p>NAC address</p>
</li>
<li>
<p>record type</p>
</li>
</ul>
<p>Following these, a variable number of fields are written, depending on the accounting record type. All are of the form <tt class="literal">attribute=value</tt>. There will always be a <tt class="literal">task_id</tt> field.</p>
<p>Current attributes are:</p>
<p><tt class="literal">unknown service start_time port elapsed_time status priv_level cmd protocol cmd-arg bytes_in bytes_out paks_in paks_out address task_id callback-dialstring nocallback-verify callback-line callback-rotary</tt></p>
<p>More may be added over time.</p>
<p>Example records (lines wrapped for legibility) are thus:</p>
<pre class="screen">1995-07-13 13:35:28 -0500  172.16.1.4  chein  tty5   198.51.100.141
        stop   task_id=12028  service=exec  port=5   elapsed_time=875
1995-07-13 13:37:04 -0500  172.16.1.4  lol    tty18  198.51.100.129
        stop   task_id=11613  service=exec  port=18  elapsed_time=909
1995-07-13 14:09:02 -0500  172.16.1.4  billw  tty18  198.51.100.152
        start  task_id=17150  service=exec  port=18
1995-07-13 14:09:02 -0500  172.16.1.4  billw  tty18  198.51.100.152
        start  task_id=17150  service=exec  port=18</pre>
<p>Elapsed time is in seconds, and is the field most people are usually interested in.</p>
<p>On the NAS, to get accounting records equivalent to previous versions of tacacs, the following is sufficient. "Stop" records contain elapsed time for connections and exec sessions.</p>
<pre class="screen">aaa accounting system default start-stop group tacacs+
aaa accounting exec default start-stop group tacacs+
aaa accounting exec acctlist stop-only group tacacs+
aaa accounting commands 15 acctlist start-stop group tacacs+
aaa accounting network acctlist stop-only group tacacs+

line XX
  accounting commands 15 acctlist</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN527" id="AEN527">4.3.1.2. Spoofing Syslog Packets</a></h5>
<p>The script <tt class="literal">tacspooflog.pl</tt> (which comes bundled with the distribution) may be used to make <tt class="literal">syslogd</tt> believe that logs come straight from your router, not from <tt class="literal">tac_plus</tt>.</p>
<p>E.g., if your <tt class="literal">syslogd</tt> is listening on <tt class="literal">127.0.0.1</tt>, you may try:</p>
<pre class="screen">  access log = "|exec sudo /path/to/tacspooflog.pl 127.0.0.1"</pre>
<p>This may be useful if you want to keep logs in a common place.</p>
<p>Please note that this will work for IPv4 only.</p>
</div>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN539" id="AEN539">4.3.2. Limits and timeouts</a></h4>
<p>A number of global limits and timeouts may be specified at realm and global level:</p>
<ul>
<li>
<p><tt class="literal">connection timeout =</tt> <span class="emphasis"><i class="emphasis">s</i></span></p>
<p>Terminate a connection to a NAS after an idle period of at least <span class="emphasis"><i class="emphasis">s</i></span> seconds.</p>
<p>Default: 600</p>
</li>
<li>
<p><tt class="literal">context timeout =</tt> <span class="emphasis"><i class="emphasis">s</i></span></p>
<p>Clears context cache entries after <span class="emphasis"><i class="emphasis">s</i></span> seconds of inactivity. Default: 3600 seconds.</p>
<p>Default: 3600</p>
</li>
<li>
<p><tt class="literal">warning period =</tt> <span class="emphasis"><i class="emphasis">d</i></span></p>
<p>Set warning period for password expiry to <span class="emphasis"><i class="emphasis">d</i></span> days.</p>
<p>Default: 14</p>
</li>
</ul>
<div class="section">
<hr>
<h5 class="section"><a name="AEN564" id="AEN564">4.3.2.1. DNS</a></h5>
<p><span class="bold"><b class="emphasis">tac_plus</b></span> can make use of static and, if compiled with <tt class="literal">c-ares</tt> support, of dynamic DNS entries. The relevant realm configuration options are:</p>
<ul>
<li>
<p><tt class="literal">dns reverse-lookup =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>This sets the global default for DNS reverse-lookups (Default: <tt class="literal">no</tt>).</p>
</li>
<li>
<p><tt class="literal">dns timeout =</tt> <span class="emphasis"><i class="emphasis">Seconds</i></span></p>
<p>This directive specifies the maximum time to wait when doing DNS reverse lookups. (Default: <tt class="literal">0</tt>).</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN583" id="AEN583">4.3.2.2. Authentication</a></h5>
<ul>
<li>
<p><tt class="literal">password</tt> ( <tt class="literal">max-attempts =</tt> <span class="emphasis"><i class="emphasis">integer</i></span> | <tt class="literal">backoff =</tt> <span class="emphasis"><i class="emphasis">seconds</i></span> | <tt class="literal">acl =</tt> <span class="emphasis"><i class="emphasis">acl</i></span> )</p>
<p><tt class="literal">backoff</tt> sets a backoff time for failed authentications. The daemon will wait for <span class="emphasis"><i class="emphasis">seconds</i></span> seconds before returning a <span class="underline"><i class="emphasis">final</i></span> authentication failure (password incorrect) message.</p>
<p>The <tt class="literal">max-attempts</tt> parameter limits the number of <tt class="literal">Password:</tt> prompts per TACACS+ session at login. It currently defaults to <tt class="literal">1</tt>, meaning that a typical login sequence with bad passwords would look like:</p>
<pre class="screen"><span class="bold"><b class="emphasis">&gt;</b></span> telnet 10.0.0.2
<span class="bold"><b class="emphasis">Trying 10.0.0.2...
Connected to 10.0.0.2.
Escape character is '^]'.

Welcome. Authorized Use Only.

Username:</b></span> admin
<span class="bold"><b class="emphasis">Password:</b></span> ***
<span class="bold"><b class="emphasis">Password incorrect.


Welcome. Authorized Use Only.

Username:</b></span> admin
<span class="bold"><b class="emphasis">Password:</b></span> ****
<span class="bold"><b class="emphasis">Password incorrect.


Welcome. Authorized Use Only.

Username:</b></span> admin
<span class="bold"><b class="emphasis">Password:</b></span> *
<span class="bold"><b class="emphasis">Password incorrect.

Connection closed by foreign host.</b></span></pre>
<p>Using, for example,</p>
<pre class="screen">password max-attempts = 3</pre>
<p>(the actual default in earlier versions was <tt class="literal">4</tt>) would change this dialog to:</p>
<pre class="screen"><span class="bold"><b class="emphasis">&gt;</b></span> telnet 10.0.0.2
<span class="bold"><b class="emphasis">Trying 10.0.0.2...
Connected to 10.0.0.2.
Escape character is '^]'.

Welcome. Authorized Use Only.

Username:</b></span> admin
<span class="bold"><b class="emphasis">Password:</b></span> ***

<span class="bold"><b class="emphasis">Password incorrect.
Password:</b></span> ****

<span class="bold"><b class="emphasis">Password incorrect.
Password:</b></span> *****

<span class="bold"><b class="emphasis">Password incorrect. Go away.


Welcome. Authorized Use Only.

Username:</b></span></pre>
<p>It's at the NAS's discretion to restart the authentication dialog with a new TACACS+ session or to close the (Telnet/SSH/...) session to the user if TACACS+ authentication fails.</p>
<p><tt class="literal">password acl</tt> may be used to perform simple compliance checks on user passwords. For example, to enforce a minimum password length of 6 characters you may try</p>
<pre class="screen">acl script = password-compliance {
    if (password =~ /^....../)
        permit
    deny
}
password acl = password-compliance</pre>
<p>Authentications using passwords that fail the check will be rejected.</p>
</li>
<li>
<p><tt class="literal">anonymous-enable =</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>Several broken <span class="emphasis"><i class="emphasis">TACACS+</i></span> implementations send no or an invalid username in <tt class="literal">enable</tt> packets. Setting this option to <tt class="literal">deny</tt> tries to enforce user authentication before enabling. This option defaults to <tt class="literal">permit</tt>.</p>
<p>Alas, this may or may not work. In theory, the enable dialog should look somewhat like:</p>
<pre class="screen">Router&gt; enable
Username: me
Password: *******
Enable Password: **********
Router#</pre>
<p>However, some implementations may resend the user password at the <tt class="literal">Enable Password:</tt> prompt. In that case you've got only two options: Either use</p>
<pre class="screen">    enable = login</pre>
<p>at user group level, which will omit the secondary password query and let the user enable with his login password, or permit anonymous <tt class="literal">enable</tt> (which is disabled by default) with</p>
<pre class="screen">    anonymous-enable = permit</pre>
<p>(globally, or at host level) and use enable passwords defined at host level.</p>
</li>
<li>
<p><tt class="literal">augmented-enable =</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>For <span class="emphasis"><i class="emphasis">TACACS+</i></span> client implementations that send <tt class="literal">$enable$</tt> instead of the real username in an enable request, this will permit user specific authentication using a concatenation of username and login password, separated with a single space character:</p>
<pre class="screen">&gt; enable
Password: myusername mypassword
#</pre>
<p><tt class="literal">enable</tt> [ <span class="emphasis"><i class="emphasis">level</i></span> ] <tt class="literal">= login</tt> needs to be set in the users' profile for this option to take effect.</p>
<p>Default: <tt class="literal">augmented-enable = deny</tt></p>
<p><tt class="literal">augmented-enable</tt> will only take effect if the NAS tries to authenticate a username matching the regex</p>
<pre class="screen">^\$enab..\$$</pre>
<p>(e.g.: <tt class="literal">$enable$</tt>, <tt class="literal">$enab15$</tt>). That matching criteria may be changed using an ACL:</p>
<pre class="screen">acl script = custom_enable_acl { if (user =~ ^demo$) permit deny }
enable user acl = custom_enable_acl</pre></li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN670" id="AEN670">4.3.2.3. Miscellaneanous</a></h5>
<ul>
<li>
<p><tt class="literal">single-connection</tt> [ <tt class="literal">may-close</tt> ] <tt class="literal">=</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>This directive may be used to permit or deny the single-connection feature. The <tt class="literal">may-close</tt> keyword tells the daemon to close a connection if it's unused (default: disabled). This directive may be overridden at host object level.</p>
</li>
<li>
<p><tt class="literal">skip conflicting groups =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>If this is set, group conflicts will be ignored in <tt class="literal">member</tt> directives. The first group defined for a given NAS wins.</p>
</li>
<li>
<p><tt class="literal">skip missing groups =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>If this is set, non-existing groups will be ignored in <tt class="literal">member</tt> directives.</p>
</li>
<li>
<p><tt class="literal">client realm =</tt> <span class="emphasis"><i class="emphasis">realm</i></span></p>
<p>Lookup NAC parameters in realm <span class="emphasis"><i class="emphasis">realm</i></span> instead of using the <tt class="literal">default</tt> one.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN704" id="AEN704">4.3.2.4. User backend options</a></h5>
<p>These options are relevant for configuring the MAVIS user backend:</p>
<ul>
<li>
<p><tt class="literal">aaa realm =</tt> <span class="emphasis"><i class="emphasis">realmName</i></span></p>
<p>Use the aaa configuration (users, groups, mavis, ...) from realm <span class="emphasis"><i class="emphasis">realm</i></span> instead of the <tt class="literal">default</tt> one.</p>
</li>
<li>
<p><tt class="literal">group realm =</tt> <span class="emphasis"><i class="emphasis">realmName</i></span></p>
<p>Use the group configuration from realm <span class="emphasis"><i class="emphasis">realm</i></span> instead of the <tt class="literal">default</tt> (or <tt class="literal">aaa</tt>) realm one.</p>
</li>
<li>
<p><tt class="literal">pap password</tt> [ <tt class="literal">default</tt> ] <tt class="literal">=</tt> ( <tt class="literal">login</tt> | <tt class="literal">pap</tt> )</p>
<p>When set to <tt class="literal">login</tt>, the PAP password default for new users will be set to use the login password.</p>
</li>
<li>
<p><tt class="literal">pap password mapping =</tt> ( <tt class="literal">login</tt> | <tt class="literal">pap</tt> )</p>
<p>When set to <tt class="literal">login</tt>, PAP authentication requests will be mapped to ASCII Login requests. You may wish to uses this for NEXUS devices.</p>
<p>May be overridden at host level.</p>
</li>
<li>
<p><tt class="literal">user backend = mavis</tt></p>
<p>Get user data from the MAVIS backend. Without that directive, only locally defined users will be available and the MAVIS backend may be used for authenticating known users (with <tt class="literal">password = mavis</tt> or simlar) only.</p>
</li>
<li>
<p><tt class="literal">pap backend = mavis</tt> [ <tt class="literal">prefetch</tt> ]</p>
<p>Verify PAP passwords using the MAVIS backend. This needs to be set to either <tt class="literal">mavis</tt> or <tt class="literal">prefetch</tt> in order to authenticate PAP requests using the MAVIS backend. If unset, the PAP password from the users' profile will be used.</p>
<p>If <tt class="literal">prefetch</tt> is specified, the daemon will first retrieve the users' profile from the backend and then authenticate the user based on information eventually found there.</p>
<p>This directive implies <tt class="literal">user backend = mavis</tt>.</p>
</li>
<li>
<p><tt class="literal">login backend = mavis</tt> [ <tt class="literal">prefetch</tt> ] [ <tt class="literal">chalresp</tt> [ <tt class="literal">noecho</tt> ] ] [ <tt class="literal">chpass</tt> ]</p>
<p>Verify Login passwords using the MAVIS backend. This needs to be set to either <tt class="literal">mavis</tt> or <tt class="literal">prefetch</tt> in order to authenticate login requests using the MAVIS backend. If unset, the login password from the users' profile will be used.</p>
<p>If <tt class="literal">prefetch</tt> is specified, the daemon will first retrieve the users' profile from the backend and then authenticate the user based on information eventually found there.</p>
<p>This directive implies <tt class="literal">user backend = mavis</tt>.</p>
<p>For use with OPIE-enabled MAVIS modules, add the <tt class="literal">chalresp</tt> keyword (and, optionally, add <tt class="literal">noecho</tt>, unless you want the typed-in response to display on the screen). Example:</p>
<pre class="screen">login backend = mavis chalresp noecho</pre>
<p>For non-local users, if the <tt class="literal">chpass</tt> attribute is set and the user provides an empty password at login, the user is given the option to change his password. This requires appropriate support in the MAVIS backend modules.</p>
</li>
<li>
<p><tt class="literal">mavis module =</tt> <span class="emphasis"><i class="emphasis">module</i></span> <tt class="literal">{</tt> ... <tt class="literal">}</tt></p>
<p>Load MAVIS module <span class="emphasis"><i class="emphasis">module</i></span>. See the MAVIS documentation for configuration guidance.</p>
</li>
<li>
<p><tt class="literal">mavis path =</tt> <span class="emphasis"><i class="emphasis">path</i></span></p>
<p>Add <span class="emphasis"><i class="emphasis">path</i></span> to the search-path for MAVIS modules.</p>
</li>
<li>
<p><tt class="literal">mavis cache timeout =</tt> <span class="emphasis"><i class="emphasis">s</i></span></p>
<p>Cache MAVIS authentication data for <span class="emphasis"><i class="emphasis">s</i></span> seconds. If <span class="emphasis"><i class="emphasis">s</i></span> is set to a value smaller than <tt class="literal">11</tt>, the dynamic user object is valid for the current TACACS+ session only. Default is <tt class="literal">120</tt> seconds.</p>
</li>
<li>
<p><tt class="literal">mavis noauthcache</tt></p>
<p>Disables password caching for MAVIS modules.</p>
</li>
<li>
<p><tt class="literal">mavis user filter =</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">acl</i></span></p>
<p>Query MAVIS user backend only if <span class="emphasis"><i class="emphasis">acl</i></span> matches. Defaults to:</p>
<pre class="screen">
acl script = __internal__username_acl__ { if (user =~ "[]&lt;&gt;/()|=[]+") deny permit }
mavis user filter = __internal__username_acl__ </pre></li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN811" id="AEN811">4.3.2.5. Railroad Diagrams</a></h5>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/RealmAttr.svg"></p>
<div class="caption">
<p>Railroad diagram: RealmAttr</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/RealmAttrAuthen.svg"></p>
<div class="caption">
<p>Railroad diagram: RealmAttrAuthen</p>
</div>
</div>
</div>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN827" id="AEN827">4.3.3. Hosts</a></h4>
<p>The daemon will talk to known NAS addresses only. Connections from unknown addresses will be rejected.</p>
<p>If you want <span class="bold"><b class="emphasis">tac_plus</b></span> to encrypt its packets (and you almost certainly <span class="emphasis"><i class="emphasis">do</i></span> want this, as there can be usernames and passwords contained in there), then you'll have to specify an (non-empty) encryption key. The identical key must also be configured on any NAS which communicates with tac_plus.</p>
<p>To specify a global key, use a statement similar to</p>
<pre class="screen">  host = 0.0.0.0/0 {
    key = "your key here"
  }</pre>
<p>or, alternatively,</p>
<pre class="screen">  host = world {
    key = "your key here"
    address = 0.0.0.0/0
  }</pre>
<p>(where <tt class="literal">world</tt> is <span class="emphasis"><i class="emphasis">not</i></span> a keyword, but just some arbitrary character string).</p>
<div class="tip">
<table class="tip" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/tip.svg" hspace="5" alt="Tip"></td>
<th align="left" valign="middle"><b>Double Quotes</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>You only need double quotes on the daemon if your key contains spaces. Confusingly, even if your key does contain spaces, you should <span class="emphasis"><i class="emphasis">never</i></span> use double quotes when you configure the matching key on the NAS.</p>
<p>The daemon will reject connections from hosts that have no encryption key defined.</p>
<p>Double quotes within double-quoted strings may be escaped using the backslash character <tt class="literal">\</tt> (which can be escaped by itself), e.g.:</p>
<pre class="screen">key = "quo\\te me\"."</pre>
<p>translates to the ASCII sequence</p>
<pre class="screen">quo\te me".</pre></td>
</tr>
</table>
</div>
<p>Any CIDR range within a host definition needs to to be unique, and the most specific definition will match. The requirement for unambiguousness is quite simply based on the fact that certain host object attributes (key, prompt, enable passwords) may only exist once.</p>
<p>On the NAS, you also need to configure the <span class="emphasis"><i class="emphasis">same</i></span> key. Do this by issuing:</p>
<pre class="screen">aaa new-model
tacacs-server host 192.168.0.1 single-connection key your key here</pre>
<p>The optional <tt class="literal">single-connection</tt> parameter specifies that multiple sessions may use the same TCP/IP connection to the server.</p>
<p>Generally, the syntax for host declarations conforms to</p>
<p><tt class="literal">host =</tt> [ <tt class="literal">realm</tt> <span class="emphasis"><i class="emphasis">realm</i></span> ] <span class="emphasis"><i class="emphasis">name_or_ip-range</i></span> { <span class="emphasis"><i class="emphasis">key-value pairs</i></span> }</p>
<p>The optional <span class="emphasis"><i class="emphasis">realm</i></span> tells the daemon to use the host definition for connections associated with a corresponding <tt class="literal">spawnd</tt> or <tt class="literal">client</tt> realm only. For example,</p>
<pre class="screen">id = spawnd {
  listen = { port = 49 }
  listen = { port = 4949 realm = space }
}

id = tac_plus {
  host = earth { address = ::/0 ... }
  host realm space = mars { address = ::/0 ... }
  group = admin { ... }
  group = alien { ... }
  user = marc { member = admin@earth member = alien@mars }
}</pre>
<p>makes group membership dependent on the address and/or port the NAS uses to contact the TACACS+ server. User <tt class="literal">marc</tt> will be a member of group <tt class="literal">admin</tt> for network access servers connecting via port 49, and member of <tt class="literal">alien</tt> for those using port 4949.</p>
<p>In most cases, hosts can be refered to either by IP address or by name.</p>
<p>The key-value pairs permitted in host sections of the configuration file are explained below.</p>
<ul>
<li>
<p><tt class="literal">key</tt> [ <tt class="literal">warn</tt> [ ( <span class="emphasis"><i class="emphasis">YYYY</i></span><tt class="literal">-</tt><span class="emphasis"><i class="emphasis">MM</i></span><tt class="literal">-</tt><span class="emphasis"><i class="emphasis">DD</i></span> | <span class="emphasis"><i class="emphasis">s</i></span> ) ] <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>This sets the key used for encrypting the communication between server and NAS. Multiple keys may be set, making key migration from one key to another pretty easy. If the <tt class="literal">warn</tt> keyword is specified, a warning message is logged when a NAS actually uses the key. Optionally, the <tt class="literal">warn</tt> keyword accepts a date argument that specifies when the warnings should start to appear in the logs.</p>
<p>During debugging, it may be convenient to temporarily switch off encryption by using an empty key:</p>
<pre class="screen">key = ""</pre>
<p>Be careful to remember to switch encryption back on again after you've finished debugging.</p>
</li>
<li>
<p><tt class="literal">usage =</tt> ( <tt class="literal">all</tt> | <tt class="literal">any</tt> | <tt class="literal">client</tt> | <tt class="literal">server</tt> | <tt class="literal">group-membership</tt>| <tt class="literal">none</tt> )</p>
<p>If set to <tt class="literal">client</tt> or <tt class="literal">none</tt>, TACACS+ session requests that originate from addresses matching the host object will be rejected. Likewise, if set to <tt class="literal">server</tt> or <tt class="literal">none</tt>, logins that originate from addresses matching the host object will be refused. If <tt class="literal">group-membership</tt> is set, the host definition may be used for group membership assignments only.</p>
<p>This setting is inherited from a supernet to its subnets and defaults to <tt class="literal">any</tt>.</p>
<div class="tip">
<table class="tip" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/tip.svg" hspace="5" alt="Tip"></td>
<th align="left" valign="middle"><b>Realms</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>You can combine <tt class="literal">usage</tt> with <span class="emphasis"><i class="emphasis">realms</i></span> to strictly separate client and server host definitions:</p>
<pre class="screen">
# A "clients"-realm that summarizes valid client addresses for authentication:
realm = clients {
        host = ::0/0 { usage = none }
        host = 172.17.2.0/24 { usage = clients }
}

# Use the "clients" realm for looking up NACs:
client realm = clients # This is the global definition, but ...

# ... the "client realm" setting can be used on a per-host basis, too:
host = router { ... client realm = clients ... }</pre></td>
</tr>
</table>
</div>
</li>
<li>
<p><tt class="literal">inherit =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>If set to <tt class="literal">no</tt>, the current host declaration won't inherit configuration snippets (e.g.: key, enable passwords) from its supernet. Default is <tt class="literal">yes</tt>.</p>
</li>
<li>
<p><tt class="literal">name =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>Assigns the name <span class="emphasis"><i class="emphasis">string</i></span> to the host object. This, combined with the <tt class="literal">address</tt> keyword, may be used to form host groups. Don't use this attribute if you've already assigned a name in the initial <tt class="literal">host =</tt> statement, and take care to define hosts <span class="emphasis"><i class="emphasis">before</i></span> users and groups, or group membership assignments may fail, possibly silently.</p>
</li>
<li>
<p><tt class="literal">address =</tt> <span class="emphasis"><i class="emphasis">cidr</i></span></p>
<p>Adds the address range specified by <span class="emphasis"><i class="emphasis">cidr</i></span> to the current host definition.</p>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/CIDR.svg"></p>
<div class="caption">
<p>Railroad diagram: CIDR</p>
</div>
</div>
</li>
<li>
<p><tt class="literal">address file =</tt> <span class="emphasis"><i class="emphasis">file</i></span></p>
<p>Add the addresses from <span class="emphasis"><i class="emphasis">file</i></span> to the current host definition. Shell wildcard patterns are expanded by <tt class="literal">glob(3)</tt>.</p>
</li>
<li>
<p><tt class="literal">client realm =</tt> <span class="emphasis"><i class="emphasis">realm</i></span></p>
<p>Lookup NAC parameters in realm <span class="emphasis"><i class="emphasis">realm</i></span> instead of using the <tt class="literal">default</tt> one.</p>
</li>
<li>
<p><tt class="literal">dns reverse-lookup =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>This directive enables or disables DNS reverse-lookups for the corresponding hosts.</p>
</li>
<li>
<p><tt class="literal">dns timeout =</tt> <span class="emphasis"><i class="emphasis">Seconds</i></span></p>
<p>This directive specifies the maximum time to wait when doing DNS reverse lookups. (Default: <tt class="literal">0</tt>).</p>
</li>
<li>
<p><tt class="literal">single-connection</tt> ( <tt class="literal">may-close</tt> ) <tt class="literal">=</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>This directive may be used to permit or deny the single-connection feature for a particular host object. The <tt class="literal">may-close</tt> keyword tells the daemon to close the connection if it's unused.</p>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Caveat Emptor</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>There's a slight chance that single-connection doesn't work as expected. The single-connection implementation in your router or even the one implemented in this daemon (or possibly both) may be buggy. If you're noticing weird AAA behaviour that can't be explained otherwise, then try disabling single-connection on the router.</p>
</td>
</tr>
</table>
</div>
</li>
<li>
<p><tt class="literal">template =</tt> ( <span class="emphasis"><i class="emphasis">address</i></span> | <span class="emphasis"><i class="emphasis">name</i></span> )</p>
<p>This uses part of an existing host definition for <span class="emphasis"><i class="emphasis">address</i></span> or <span class="emphasis"><i class="emphasis">name</i></span> as template for the current host declaration. Only <tt class="literal">banner</tt>s, <tt class="literal">key</tt>, <tt class="literal">enable</tt> passwords and <tt class="literal">content</tt> are copied, and no recursive lookups take place.</p>
</li>
</ul>
<div class="section">
<hr>
<h5 class="section"><a name="AEN996" id="AEN996">4.3.3.1. Timeouts</a></h5>
<p>The connection timeout may be specified:</p>
<ul>
<li>
<p><tt class="literal">connection timeout =</tt> <span class="emphasis"><i class="emphasis">s</i></span></p>
<p>Terminate a connection to this NAS after an idle period of at least <span class="emphasis"><i class="emphasis">s</i></span> seconds. Defaults to the global option.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1006" id="AEN1006">4.3.3.2. Authentication</a></h5>
<p>The following authentication related directives are available at host object level:</p>
<ul>
<li>
<p><tt class="literal">aaa realm =</tt> <span class="emphasis"><i class="emphasis">realmName</i></span></p>
<p>Use the aaa configuration (users, groups, mavis, ...) from realm <span class="emphasis"><i class="emphasis">realm</i></span> instead of the <tt class="literal">default</tt> one.</p>
</li>
<li>
<p><tt class="literal">access acl =</tt> ( [ <tt class="literal">permit</tt> ] | <tt class="literal">deny</tt> ) [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">acl</i></span></p>
<p>Authentication requests not matching this directive will be rejected.</p>
</li>
<li>
<p><tt class="literal">password</tt> ( <tt class="literal">max-attempts =</tt> <span class="emphasis"><i class="emphasis">integer</i></span> | <tt class="literal">backoff =</tt> <span class="emphasis"><i class="emphasis">seconds</i></span> )</p>
<p>The <tt class="literal">max-attempts</tt> option sets the maximum number of <tt class="literal">Password:</tt> prompts per session. Likewise, <tt class="literal">backoff</tt> specifies the (host-specific) delay before returning a <tt class="literal">Password incorrect.</tt> message and closing the session.</p>
<p>Setting these parameters here overrides the corresponding global options, which come with a more exhaustive explanation.</p>
<p><tt class="literal">backoff</tt> can be specified for both NAC and NAS host objects. If both are given, the smaller one wins.</p>
</li>
<li>
<p><tt class="literal">pap password mapping =</tt> ( <tt class="literal">login</tt> | <tt class="literal">pap</tt> )</p>
<p>When set to <tt class="literal">login</tt>, PAP authentication requests will be mapped to ASCII Login requests. You may wish to uses this for NEXUS devices.</p>
</li>
<li>
<p><tt class="literal">default user =</tt> <tt class="literal">name</tt></p>
<p>This directive sets a default user name for connections sourced from hosts matching this host object. For example:</p>
<pre class="screen">host = nms { address = 1.2.3.4 user = nmsuser }</pre>
<p>will tell the daemon not to query for the user name for connections coming from <tt class="literal">1.2.3.4</tt>, but to use <tt class="literal">nmsuser</tt> instead.</p>
<p>Use this option with care. It may come handy while transitioning to a TACACS+ environment, but has several severe implications, the first one being that the router has no idea about the username, which implies that authorization via TACACS+ won't work.</p>
</li>
<li>
<p><tt class="literal">default group =</tt> <tt class="literal">name</tt></p>
<p>For users without any group membership this directive may be used to assign one; it's used for connections originating from this host object. For example, you can deny access to user without group membership by using something like that:</p>
<pre class="screen">  host = ... { default group = no_login }
  acl script = no_login { deny }
  group = no_login { acl = no_login }</pre></li>
<li>
<p><tt class="literal">enable</tt> [ <span class="emphasis"><i class="emphasis">level</i></span> ] <tt class="literal">=</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> | <tt class="literal">login</tt> | ( <tt class="literal">clear</tt> | <tt class="literal">crypt</tt>) <span class="emphasis"><i class="emphasis">password</i></span> )</p>
<p>This directive may be used to set host specific enable passwords, to use the <span class="emphasis"><i class="emphasis">login</i></span> password, or to permit (without password) or refuse any enable attempt. <span class="emphasis"><i class="emphasis">level</i></span> defaults to 15.</p>
<p>Enable passwords specified at host level have a lower precedence as those defined at user or group level.</p>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Password Hashes</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>You can use the <tt class="literal">openssl passwd</tt> utility to compute password hashes. For example,</p>
<pre class="screen">openssl passwd -1 <span class="emphasis"><i class="emphasis">clear_text_password</i></span></pre>
<p>returns a MD5 hash.</p>
</td>
</tr>
</table>
</div>
<p>You can enable via TACACS+ by configuring on the NAS:</p>
<pre class="screen">aaa authentication enable default group tacacs+ enable</pre></li>
<li>
<p><tt class="literal">anonymous-enable =</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>Several broken <span class="emphasis"><i class="emphasis">TACACS+</i></span> implementations send no or an invalid username in <tt class="literal">enable</tt> packets. Setting this option to <tt class="literal">deny</tt> enforces user authentication before enabling. Setting this option here has precedence over the global option.</p>
</li>
<li>
<p><tt class="literal">augmented-enable =</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>For <span class="emphasis"><i class="emphasis">TACACS+</i></span> client implementations that send <tt class="literal">$enable$</tt> instead of the real username in an enable request, this will permit user specific authentication using a concatenation of username and login password, separated with a single space character. Setting this option here has precedence over the global option.</p>
<p><tt class="literal">enable</tt> [ <span class="emphasis"><i class="emphasis">level</i></span> ] <tt class="literal">= login</tt> needs to be set in the users' profile for this option to take effect.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1108" id="AEN1108">4.3.3.3. Authorization</a></h5>
<p>The following authorization related directives are available at host object level:</p>
<ul>
<li>
<p><tt class="literal">permit if-authenticated =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>This will cause authorization for users unknown to the daemon to succeed (e.g. when logging in locally while the daemon is down or while initially configuring TACACS+ support and messing up).</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1118" id="AEN1118">4.3.3.4. Banners and Messages</a></h5>
<p>The daemon allows for various banners to be diplayed to the user:</p>
<ul>
<li>
<p><tt class="literal">welcome banner =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
</li>
<li>
<p><tt class="literal">motd banner =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
</li>
<li>
<p><tt class="literal">failed authentication banner =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>The <tt class="literal">failed authentication banner</tt> gets displayed upon final failure of an authentication attempt.</p>
</li>
<li>
<p><tt class="literal">reject banner =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>The <tt class="literal">reject banner</tt> gets displayed in place of the welcome message if a connection was rejected by an <tt class="literal">access</tt> ACL defined at host, user or group level.</p>
</li>
<li>
<p><tt class="literal">message =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
</li>
</ul>
<p>The time when those texts get displayed largely depends on the actual login method:</p>
<div class="informaltable"><a name="AEN1148" id="AEN1148"></a>
<table border="1" frame="border" class="CALSTABLE">
<col>
<col>
<col>
<col>
<col>
<thead>
<tr>
<th>Context</th>
<th>Directive</th>
<th>Login via Telnet</th>
<th>Login via SSHv1</th>
<th>Login via SSHv2</th>
</tr>
</thead>
<tbody>
<tr>
<td><tt class="literal">host</tt></td>
<td><tt class="literal">welcome banner</tt></td>
<td>
<p>displayed before</p>
<p><tt class="literal">Username:</tt></p>
</td>
<td>not displayed</td>
<td>
<p>displayed before</p>
<p><tt class="literal">Password:</tt></p>
</td>
</tr>
<tr>
<td><tt class="literal">host</tt></td>
<td><tt class="literal">reject banner</tt></td>
<td>displayed before closing connection</td>
<td>not displayed</td>
<td>not displayed</td>
</tr>
<tr>
<td><tt class="literal">host</tt></td>
<td><tt class="literal">motd banner</tt></td>
<td>displayed after successful login</td>
<td>not displayed</td>
<td>displayed after successful login</td>
</tr>
<tr>
<td><tt class="literal">host</tt></td>
<td><tt class="literal">failed authentication banner</tt></td>
<td>displayed after unsuccessful login</td>
<td>not displayed</td>
<td>displayed after unsuccessful login</td>
</tr>
<tr>
<td><tt class="literal">user</tt> or <tt class="literal">group</tt></td>
<td><tt class="literal">message</tt></td>
<td>
<p>displayed after</p>
<p><tt class="literal">motd banner</tt></p>
</td>
<td>not displayed</td>
<td>
<p>displayed after</p>
<p><tt class="literal">motd banner</tt></p>
</td>
</tr>
</tbody>
</table>
</div>
<p>Neither the <tt class="literal">motd banner</tt> nor a <tt class="literal">message</tt> defined in the users' profile will be displayed if <tt class="literal">hushlogin</tt> is set for the user.</p>
<p>Both banners and messages support <tt class="literal">strftime(3)</tt>-style conversion specifications, plus the following conversion sequences:</p>
<div class="informaltable"><a name="AEN1217" id="AEN1217"></a>
<table border="1" class="CALSTABLE">
<col width="20%" title="col1">
<col width="80%" title="col2">
<tbody>
<tr>
<td><tt class="literal">%%r</tt></td>
<td>router address</td>
</tr>
<tr>
<td><tt class="literal">%%R</tt></td>
<td>router DNS name (fallback: IP address)</td>
</tr>
<tr>
<td><tt class="literal">%%c</tt></td>
<td>client address</td>
</tr>
<tr>
<td><tt class="literal">%%C</tt></td>
<td>client DNS name (fallback: IP address)</td>
</tr>
<tr>
<td><tt class="literal">%%p</tt></td>
<td>router port</td>
</tr>
<tr>
<td><tt class="literal">%%u</tt></td>
<td>username</td>
</tr>
<tr>
<td><tt class="literal">%%%</tt></td>
<td>literal <tt class="literal">%</tt></td>
</tr>
</tbody>
</table>
</div>
<p>Example:</p>
<pre class="screen">  host = <span class="emphasis"><i class="emphasis">...</i></span> {
    <span class="emphasis"><i class="emphasis">...</i></span>
    welcome banner = "Welcome. Today is %A.\n"
    <span class="emphasis"><i class="emphasis">...</i></span>
  }</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1256" id="AEN1256">4.3.3.5. Workarounds for Client Bugs</a></h5>
<p>The directive</p>
<p><tt class="literal">client bug =</tt> <span class="emphasis"><i class="emphasis">value</i></span></p>
<p>may improve compatibility with clients that violate the protocol. Currently, the following bit values (yes, you can use bitwise OR here) are recognized:</p>
<div class="informaltable"><a name="AEN1263" id="AEN1263"></a>
<table border="1" frame="border" class="CALSTABLE">
<col width="5%" title="col1">
<col width="5%" title="col2">
<col width="90%" title="col3">
<thead>
<tr>
<th>Bit</th>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>1</td>
<td>Ignore invalid AUTHEN/START data, seen with ZTE devices that put their MAC address there.</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>Accept version 1 for authorization and accounting packets, seen with Palo Alto systems.</td>
</tr>
</tbody>
</table>
</div>
<p>Example:</p>
<pre class="screen">  host = <span class="emphasis"><i class="emphasis">...</i></span> {
    <span class="emphasis"><i class="emphasis">...</i></span>
    client bug = 2
    <span class="emphasis"><i class="emphasis">...</i></span>
  }</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1287" id="AEN1287">4.3.3.6. Inheritance and Hosts</a></h5>
<p>For host lookups, the daemon looks for the most specific host definition first. If that definition (or the requested value) doesn't exist, it looks for the next less-specific one. This process continues through the entire (IPv6) CIDR hierarchy, until a match is found.</p>
<p>In other words: For host parameters, the most specific host definition with that parameter defined matches.</p>
<p>For example, if a host <tt class="literal">192.168.1.15</tt> connects to the server, the server needs to know which encryption key to use.</p>
<p>In IPv6-mapped CIDR notation (which the daemon uses internally), the IPv4 CIDR range</p>
<pre class="screen">192.168.1.15/32</pre>
<p>equals</p>
<pre class="screen">0000:0000:0000:0000:0000:FFFF:C0A8:010F/128</pre>
<p>The daemon will search for a key in the host definition for <tt class="literal">192.168.1.15</tt> and the (defined) supernets:</p>
<pre class="screen">0000:0000:0000:0000:0000:FFFF:C0A8:010F/128
0000:0000:0000:0000:0000:FFFF:C0A8:010F/127
0000:0000:0000:0000:0000:FFFF:C0A8:010E/126
0000:0000:0000:0000:0000:FFFF:C0A8:010C/125
...
0000:0000:0000:0000:0000:FFFF:C000:0000/98
0000:0000:0000:0000:0000:FFFF:8000:0000/97
0000:0000:0000:0000:0000:FFFF:0000:0000/96
0000:0000:0000:0000:0000:FFFE:0000:0000/95
0000:0000:0000:0000:0000:FFFC:0000:0000/94
...
0000:0000:0000:0000:0000:0000:0000:0000/3
0000:0000:0000:0000:0000:0000:0000:0000/2
0000:0000:0000:0000:0000:0000:0000:0000/1
0000:0000:0000:0000:0000:0000:0000:0000/0</pre>
<p>The first key found will be used, as it is the most specific one.</p>
<p>By default, <tt class="literal">welcome banner</tt>, <tt class="literal">motd banner</tt>, <tt class="literal">key</tt>, <tt class="literal">enable</tt>, <tt class="literal">anonymous-enable</tt> and <tt class="literal">content</tt> specifications are inherited. Inheritance may be switched off for a host object:</p>
<pre class="screen">    inherit = no</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1309" id="AEN1309">4.3.3.7. Railroad Diagrams</a></h5>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/HostDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: HostDecl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/HostAttr.svg"></p>
<div class="caption">
<p>Railroad diagram: HostAttr</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/EnableExpr.svg"></p>
<div class="caption">
<p>Railroad diagram: EnableExpr</p>
</div>
</div>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1332" id="AEN1332">4.3.3.8. Example</a></h5>
<pre class="screen">host = 10.0.0.0/8 {
    name = customer1
    key = "your key here"
    welcome banner = "\nHitherto shalt thou come, but no further. (Job 38.11)\n\n"
    enable 15 = clear whatever
}

host = test123 {
    address = 10.1.2.0/28
    address = 10.12.1.30/28
    address = 10.1.1.2
    # key/banners/enable will be inherited from 10.0.0.0/8 by default,
    # unless you specify "inherit = no"
    address file = /some/path/test123.cidr
    prompt = "\nGo away.\n\n"
}</pre></div>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN1335" id="AEN1335">4.3.4. Time Ranges</a></h4>
<p><tt class="literal">timespec</tt> objects may be used for time based profile assignments. Both <tt class="literal">cron</tt> and <tt class="literal">Taylor-UUCP</tt> syntax are supported; see you local <tt class="literal">crontab</tt><span class="emphasis"><i class="emphasis">(5)</i></span> and/or UUCP man pages for details. Syntax:</p>
<p><tt class="literal">timespec =</tt> <span class="emphasis"><i class="emphasis">timespec_name</i></span> <tt class="literal">{ "</tt><span class="emphasis"><i class="emphasis">entry</i></span><tt class="literal">"</tt> [ ... ] <tt class="literal">}</tt></p>
<p>Example:</p>
<pre class="screen"># Working hours are from Mo-Fr from 9 to 16:59, and
# on Saturdays from 9 to 12:59:
timespec = workinghours {
    "* 9-16 * * 1-5"   # or: "* 9-16 * * Mon-Fri"
    "* 9-12 * * 6"     # or: "* 9-12 * * Sat"
}

timespec = sunday { "* * * * 0" }

timespec = example {
    Wk2305-0855,Sa,Su2305-1655
    Wk0905-2255,Su1705-2255
    Any
}</pre>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1352" id="AEN1352">4.3.4.1. Railroad Diagrams</a></h5>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/TimespecDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: TimespecDecl</p>
</div>
</div>
</div>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN1361" id="AEN1361">4.3.5. Access Control Lists</a></h4>
<p>Access Control Lists (ACLs) consist of a series of Access Control Expressions (ACEs). An ACL does match whenever one of its ACEs does. The ACEs that form an ACL are processed in sequence. An ACE matches if at least one of each defined subtype expression type matches. ACEs named identially become part of an ACL with the same name.</p>
<p>Standard ACL syntax is:</p>
<p><tt class="literal">acl</tt> <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">name</i></span> <tt class="literal">{</tt> ( (<tt class="literal">nac</tt> ( <tt class="literal">=</tt> [ <tt class="literal">not</tt> ] (<span class="emphasis"><i class="emphasis">HostName</i></span>|<span class="emphasis"><i class="emphasis">cidr</i></span>) ) | ( [ <tt class="literal">dns</tt> ] <tt class="literal">regex =</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">NacRegex</i></span> )) | (<tt class="literal">nas</tt> ( <tt class="literal">=</tt> [ <tt class="literal">not</tt> ] (<span class="emphasis"><i class="emphasis">HostName</i></span>|<span class="emphasis"><i class="emphasis">cidr</i></span>) ) | (<tt class="literal">regex =</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">NasRegex</i></span> )) | (<tt class="literal">port regex =</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">PortRegex</i></span> ) | (<tt class="literal">acl =</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">ACLName</i></span> )* <tt class="literal">}</tt> (<tt class="literal">time =</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">TimeSpecName</i></span> )* <tt class="literal">}</tt></p>
<p>Alternatively, scripting can be used:</p>
<p><tt class="literal">acl script =</tt> <span class="emphasis"><i class="emphasis">name</i></span> <tt class="literal">{</tt> ... <tt class="literal">}</tt></p>
<p>The latter is detailled in the next chapter.</p>
<p>For standard ACL syntax, please have a look at the Railroad Diagrams below, and things will hopefully become much clearer.</p>
<p>ACEs will be evaluated in the order you've defined them. E.g.,</p>
<pre class="screen">acl = myacl {
    nac = 10.0.0.0/8
    nac = 11.0.0.0/8
    nas = somehostobjectname
}

acl = myacl {
    time = workinghours
}</pre>
<p>consists of two ACEs which form an ACL named "myacl". This ACL matches</p>
<ul>
<li>
<p>for clients in 10.0.0.0/8 or in 11.0.0.0/8, and servers part of <tt class="literal">somehostobjectname</tt></p>
</li>
<li>
<p>or simply during <tt class="literal">workinghours</tt>, no matter what clients or servers (or, for that matter, ports) are involved.</p>
</li>
</ul>
<p>When using the <tt class="literal">dns</tt> keyword, NAC regex matching is done against the NACs DNS reverse mapping. This will only work if the software was compiled with <tt class="literal">c-ares</tt> support. However, keep in mind that DNS isn't necessarily trustworthy and lookups might plain fail. Keep in mind that you're best off enabling <tt class="literal">single-connection</tt> on your NAS. This allows the daemon to take advantage of caching the reverse-mapping results.</p>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1420" id="AEN1420">4.3.5.1. Railroad Diagrams</a></h5>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ACLDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: ACLDecl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ACLExpr.svg"></p>
<div class="caption">
<p>Railroad diagram: ACLExpr</p>
</div>
</div>
</div>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN1436" id="AEN1436">4.3.6. Rewriting User Names</a></h4>
<p>This is experimental. It requires the binary to be built with PCRE v2 support (using the <tt class="literal">--with-pcre2</tt> configure option).</p>
<p>A host may refer to a rewrite profile defined at realm level to substitute user names. The following sample code will map both <tt class="literal">admin</tt> and <tt class="literal">root</tt> to <tt class="literal">marc</tt>, and convert all other usernames to lower-case:</p>
<pre class="screen">rewrite = rewriteRule {
    rewrite /^admin$/ marc
    rewrite /^root$/ marc
    rewrite /^.*$/ \L$0
}

host = ... {
    ...
    rewrite user = rewriteRule
    ...
}</pre>
<p>Please keep in mind that this is experimental ...</p>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN1446" id="AEN1446">4.3.7. Scripts</a></h4>
<p>Scripts may currently be used for ACLs and in service declaration scope:</p>
<ul>
<li>
<p><tt class="literal">acl script =</tt> acl_name <tt class="literal">{</tt> tac_action ... <tt class="literal">}</tt></p>
<p>Example:</p>
<pre class="screen">    acl script = myacl123 {
        if (nas == 1.2.3.4 || nac = SomeHostName || nac-dns =~ /\\.example\\.com$/) deny
    }</pre></li>
<li>
<p><tt class="literal">script = {</tt> tac_action ... <tt class="literal">}</tt></p>
<p>Example:</p>
<pre class="screen">    user = joe {
        service = shell {
            script = {
                if (cmd == "") permit # required for shell startup
                if (cmd =~ /^(no\s)?shutdown\s/) permit }
        }
    }</pre></li>
</ul>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1463" id="AEN1463">4.3.7.1. Syntax</a></h5>
<p>A script consists of a series of actions:</p>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/TacAction.svg"></p>
<div class="caption">
<p>Railroad diagram: TacAction</p>
</div>
</div>
<p>The actions <tt class="literal">return</tt>, <tt class="literal">permit</tt> and <tt class="literal">deny</tt> are final. At the end of a script, <tt class="literal">return</tt> is implied, at which the daemon continues processing the configured <tt class="literal">cmd</tt> statements in <tt class="literal">shell</tt> context) or standard ACLs (in ACL context). The assignment operations (<tt class="literal">context =</tt>, <tt class="literal">message =</tt>) do make sense in <tt class="literal">shell</tt> context only.</p>
<p>Setting the <tt class="literal">context</tt> variable makes sense in <tt class="literal">shell</tt> context only. See the example in the corresponding section.</p>
<p>Condition syntax is:</p>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/TacCond.svg"></p>
<div class="caption">
<p>Railroad diagram: TacCond</p>
</div>
</div>
<p><tt class="literal">cmd</tt> and <tt class="literal">context</tt> may be used in <tt class="literal">shell</tt> context only.</p>
</div>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN1498" id="AEN1498">4.3.8. Users and Groups</a></h4>
<p>User and group declarations are pretty similar. The major difference is, that groups are <span class="emphasis"><i class="emphasis">static</i></span>, while user declarations may be added at run-time via the <span class="emphasis"><i class="emphasis">MAVIS</i></span> back-end.</p>
<p>A user may be member of a group (also known as <span class="emphasis"><i class="emphasis">role</i></span> or <span class="emphasis"><i class="emphasis">profile</i></span>). Actual group membership may depend on various factors, e.g. the NAS the user is on, the NAC, or time ranges. Each group may in turn be member of another group and so on, ad infinitum.</p>
<p>The basic form of a user and group declarations is</p>
<pre class="screen">user = <span class="emphasis"><i class="emphasis">username</i></span> { <span class="emphasis"><i class="emphasis">... </i></span> }</pre>
<p>or, respectively,</p>
<pre class="screen">group = <span class="emphasis"><i class="emphasis">groupname</i></span> { <span class="emphasis"><i class="emphasis"> ... </i></span> }</pre>
<p>A user or group declaration may contain key-value pairs and service declarations.</p>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1515" id="AEN1515">4.3.8.1. User-only options</a></h5>
<p>The following declarations are valid in <span class="emphasis"><i class="emphasis">user</i></span> context only:</p>
<ul>
<li>
<p><tt class="literal">login =</tt> ( ( <tt class="literal">clear</tt> | <tt class="literal">crypt</tt> ) <span class="emphasis"><i class="emphasis">password</i></span> | <tt class="literal">mavis</tt> | <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>The <tt class="literal">login</tt> password authenticates <tt class="literal">shell</tt> log-ins to the server.</p>
<pre class="screen">login = crypt aFtFBT4e5muQE
login = clear Ci5c0</pre>
<p>For <tt class="literal">crypt</tt>, DES- or MD5-hashed passwords may be used.</p>
<p>If the <tt class="literal">mavis</tt> keyword is used instead, the password will be looked up via the <span class="bold"><b class="emphasis">MAVIS</b></span> backend. It will not be cached. This functionality may be useful if you want to authenticate at external systems, despite static user declarations in the configuration file.</p>
</li>
<li>
<p><tt class="literal">pap =</tt> ( ( <tt class="literal">clear</tt> | <tt class="literal">crypt</tt> ) <span class="emphasis"><i class="emphasis">password</i></span> | <tt class="literal">mavis</tt> | <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>The <tt class="literal">pap</tt> authenticates PAP log-ins to the server. Just like with <tt class="literal">login</tt>, the password doesn't need to be in clear text, but may be DES (or MD5) hashed, or may be looked up via the <span class="bold"><b class="emphasis">MAVIS</b></span> backend.</p>
</li>
<li>
<p><tt class="literal">arap =</tt> ( <tt class="literal">clear</tt><span class="emphasis"><i class="emphasis">password</i></span> | <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>For ARAP authentication, a cleartext password is required.</p>
</li>
<li>
<p><tt class="literal">chap =</tt> ( <tt class="literal">clear</tt><span class="emphasis"><i class="emphasis">password</i></span> | <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>For CHAP authentication, a cleartext password is required.</p>
</li>
<li>
<p><tt class="literal">ms-chap =</tt> ( <tt class="literal">clear</tt><span class="emphasis"><i class="emphasis">password</i></span> | <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>For MS-CHAP authentication, a cleartext password is required.</p>
</li>
<li>
<p><tt class="literal">password =</tt> ( <tt class="literal">clear</tt><span class="emphasis"><i class="emphasis">password</i></span> | <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>This directive sets all <span class="emphasis"><i class="emphasis">previously undefined</i></span> passwords to the given cleartext password. This directive is retained for backwards compatibility only, and usage is deprecated.</p>
</li>
<li>
<p><tt class="literal">password</tt> [ <tt class="literal">acl</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">acl</i></span> ] <tt class="literal">{</tt> ... <tt class="literal">}</tt></p>
<p>This directive allows specification of ACL-dependent passwords. Example:</p>
<pre class="screen">acl jumpstation = { nac == 10.255.0.85 }

user = marc {
    password acl jumpstation {
        login = permit
        pap = permit
    }
    password {
        login = clear myLoginPassword
        pap = clear myPapPassword
    }
}</pre></li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1594" id="AEN1594">4.3.8.2. Group-only options</a></h5>
<p>The following declarations are valid in <span class="emphasis"><i class="emphasis">group</i></span> context only:</p>
<ul>
<li>
<p><tt class="literal">template =</tt> <span class="emphasis"><i class="emphasis">groupname</i></span></p>
<p>This directive merges group definitions from <span class="emphasis"><i class="emphasis">groupname</i></span> to the current group. Already existing definitions take precedence.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1605" id="AEN1605">4.3.8.3. User and Group options</a></h5>
<p>The following key-value pairs are valid in both <span class="emphasis"><i class="emphasis">user</i></span> and <span class="emphasis"><i class="emphasis">group</i></span> context:</p>
<div class="section">
<hr>
<h6 class="section"><a name="AEN1610" id="AEN1610">4.3.8.3.1. Limits</a></h6>
<p>Validity of an user or group may be limited by various attributes:</p>
<ul>
<li>
<p><tt class="literal">acl =</tt> ( [ <tt class="literal">permit</tt> ] | <tt class="literal">deny</tt> ) [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">acl</i></span></p>
<p>Validity of of a user or group profile may be restricted by ACLs. Multiple ACLs may be specified and are evaluated in order.</p>
</li>
<li>
<p><tt class="literal">valid from =</tt> ( <span class="emphasis"><i class="emphasis">YYYY</i></span><tt class="literal">-</tt><span class="emphasis"><i class="emphasis">MM</i></span><tt class="literal">-</tt><span class="emphasis"><i class="emphasis">DD</i></span> | <span class="emphasis"><i class="emphasis">s</i></span> )</p>
<p>The profile will be valid starting at the given date, which can be specified either in ISO8601 date format or as in seconds since January 1, 1970, UTC.</p>
</li>
<li>
<p><tt class="literal">valid until =</tt> ( <span class="emphasis"><i class="emphasis">YYYY</i></span><tt class="literal">-</tt><span class="emphasis"><i class="emphasis">MM</i></span><tt class="literal">-</tt><span class="emphasis"><i class="emphasis">DD</i></span> | <span class="emphasis"><i class="emphasis">s</i></span> )</p>
<p>The profile will be invalid after the given date.</p>
</li>
<li>
<p><tt class="literal">client</tt> [ <tt class="literal">regex</tt> ] <tt class="literal">=</tt> ( <tt class="literal">deny</tt> | [ <tt class="literal">permit</tt> ] ) <span class="emphasis"><i class="emphasis">string</i></span> [ <tt class="literal">,</tt> ... ]</p>
<p>As an alternative (or complement) to ACLs (see above), certain NAC based validity restrictions may be placed in a user (or group) object directly. For example, to limit log-ins to a certain IP range or a host group:</p>
<pre class="screen">    client = 10.99.0.0/16
    client = deny customer3</pre>
<p>If the <tt class="literal">regex</tt> keyword is used, <span class="emphasis"><i class="emphasis">string</i></span> is expected to be a valid regular expression. Regular expression search is expensive and only used if the NAC address sent by the NAS ist <span class="emphasis"><i class="emphasis">not</i></span> an IP address. Example for regular expression client matching:</p>
<pre class="screen">    # if compiled with PCRE:
    client = deny /^async$/
    client regex = /^console$/

    # without PCRE:
    client = deny "^async$"
    client regex = "^console$"
</pre>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Evaluation Order</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>Please keep in mind that ACLs are checked <span class="emphasis"><i class="emphasis">before</i></span> <tt class="literal">client</tt> statements.</p>
<p>For <tt class="literal">client</tt> definitions, IP addresses are checked <span class="emphasis"><i class="emphasis">before</i></span> regular expressions, while the latter are evaluated in the order you've defined them.</p>
</td>
</tr>
</table>
</div>
</li>
<li>
<p><tt class="literal">server =</tt> ( <tt class="literal">deny</tt> | [ <tt class="literal">permit</tt> ] ) <span class="emphasis"><i class="emphasis">string</i></span> [ <tt class="literal">,</tt> ... ]</p>
<p>This limits user account validity to certain NAS addresses or groups, e.g.:</p>
<pre class="screen">    server = 1.2.3.4/32
    server = nas01</pre></li>
</ul>
</div>
<div class="section">
<hr>
<h6 class="section"><a name="AEN1675" id="AEN1675">4.3.8.3.2. Messages</a></h6>
<p>These options handle displaying of messages to the user.</p>
<ul>
<li>
<p><tt class="literal">message =</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>A message displayed to the user upon log-in.</p>
</li>
<li>
<p><tt class="literal">hushlogin =</tt> ( <tt class="literal">yes</tt> | <tt class="literal">no</tt> )</p>
<p>Setting <tt class="literal">hushlogin</tt> to <tt class="literal">yes</tt> keeps the daemon from displaying <tt class="literal">motd</tt> and <tt class="literal">user</tt> messages upon login.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h6 class="section"><a name="AEN1694" id="AEN1694">4.3.8.3.3. Enable passwords</a></h6>
<p>Enable passwords may be specified at, in order of preference, host, user or group level:</p>
<ul>
<li>
<p><tt class="literal">enable</tt> [ <span class="emphasis"><i class="emphasis">level</i></span> ] <tt class="literal">=</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> | <tt class="literal">login</tt> | ( <tt class="literal">clear</tt> | <tt class="literal">crypt</tt> ) <span class="emphasis"><i class="emphasis">password</i></span> )</p>
<p>This directive may be used to set user or group specific enable passwords, to use the <span class="emphasis"><i class="emphasis">login</i></span> password, or to permit (without password) or refuse any enable attempt. Enable secrets defined at group or user level have precedence over those defined at host level. <span class="emphasis"><i class="emphasis">level</i></span> defaults to 15.</p>
<p>The default privilege level for an ordinary user on the NAS is usually 1. When a user enables, she can reset this level to a value between 0 and 15 by using the NAS <tt class="literal">enable</tt> command. If she doesn't specify a level, the default level she enables to is 15.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h6 class="section"><a name="AEN1714" id="AEN1714">4.3.8.3.4. MAVIS options</a></h6>
<p>The following <span class="emphasis"><i class="emphasis">MAVIS</i></span> related option is available for groups and locally defined users:</p>
<ul>
<li>
<p><tt class="literal">mavis realm =</tt> <span class="emphasis"><i class="emphasis">realmName</i></span></p>
<p>For locally defined users with <tt class="literal">password = mavis</tt> (or one if its variations) this directive selects the realm to use for <span class="emphasis"><i class="emphasis">MAVIS</i></span> authentications.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h6 class="section"><a name="AEN1726" id="AEN1726">4.3.8.3.5. Group membership</a></h6>
<p>Group membership is specified using the <tt class="literal">member</tt> directive:</p>
<ul>
<li>
<p><tt class="literal">member</tt> [ <tt class="literal">acl</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">acl</i></span> ] <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">string</i></span> [ <tt class="literal">,</tt> ... ]</p>
<p>This directive defines group membership, optionally depending on the NAS server's address or on some access list. For example, you could configure:</p>
<pre class="screen">host = campus { ... }
host = remote { ... }
host = router { ... }
timespec = workinghours { ... }
group = admins { ... }
group = staff { ... }
group = guest { ... }</pre>
<p>plus a couple of ACLs:</p>
<pre class="screen">acl oncampus = { nac = campus }
acl viavpn = { nac = remote }
acl atwork = { nac = campus time = workinghours }</pre>
<p>and then base group membership on the latter:</p>
<pre class="screen">user = adminuser { member = admins }
user = employee {
    ...
    member acl atwork = staff@router
    member acl viavpn = staff
    member acl remote = guest
    ...
}
user = guest {
    ...
    member acl atwork = guest
    ...
}
user = myself {
    ...
    member = admins@router
    member = staff
    ...
}</pre>
<p><tt class="literal">member</tt> directives are to be ordered by ACL name, with definitions without ACL coming last. This is enforced at parsing time.</p>
<p>Alternate groups may be specified, with group names separated by <tt class="literal">/</tt>:</p>
<pre class="screen">member = dialin/callback@10.11.12.13</pre>
<p>Here, group membership will default to the <tt class="literal">dialin</tt> group. However, appending the <span class="emphasis"><i class="emphasis">separation character</i></span> <tt class="literal">*</tt> (changeable using the <tt class="literal">separation tag =</tt> <span class="emphasis"><i class="emphasis">character</i></span> directive), followed by <tt class="literal">callback</tt> to the username <span class="emphasis"><i class="emphasis">at login time</i></span> will choose the corresponding <tt class="literal">callback</tt> group profile instead.</p>
<p>To iterate this again: Any user can be a member of exactly one primary group. The <tt class="literal">dialin/callback</tt> syntax in this example actually means: The user is free to choose at <span class="emphasis"><i class="emphasis">login time</i></span> whether he wants to be a member of <tt class="literal">dialin</tt> XOR <tt class="literal">callback</tt>. User <tt class="literal">fred</tt> may authenticate as <tt class="literal">fred</tt> (or as <tt class="literal">fred*dialin</tt>) to gain <tt class="literal">dialin</tt> membership, and <tt class="literal">fred*callback</tt> will assign him to the <tt class="literal">callback</tt> group.</p>
<p>The users' choice can be overridden using the <tt class="literal">tag</tt> directive (see below).</p>
<p>Group membership may depend on NAS IP, e.g. <tt class="literal">fred</tt> could have something like</p>
<pre class="screen">member = test1@nas1
member = test2@nas2
</pre>
<p>in his profile.</p>
<p>Just like users, groups can be member of (other) groups:</p>
<pre class="screen">group = test1 { ... }
group = test2 { ... }
                                                                                       
group = test2 {
   ...
   member = test1
   member = test2@nas1
   ...
}
</pre>
<p>Simultaneous membership in (non-hierarchical) groups isn't supported.</p>
<p>As group membership is resolved when parsing the configuration file, groups and hosts need to be already defined before being used as argument in a <tt class="literal">member</tt> definition.</p>
</li>
<li>
<p><tt class="literal">nas default restriction =</tt> ( <span class="emphasis"><i class="emphasis">cidr</i></span> | <span class="emphasis"><i class="emphasis">host</i></span> )</p>
<p>Limits usage of the group to the specified hosts, unless specified otherwise. Example:</p>
<pre class="screen">group = group1 { nas default restriction = host1 }
group = group2 { }
group = group3 { nas default restriction = host1 }
user = user1 { member = group1,group2,group3@host3 }</pre>
<p>is identical to</p>
<pre class="screen">group = group1 { }
group = group2 { }
group = group3 { }
user = user1 { member = group1@host1,group2,group3@host3 }</pre>
<p>Note: <tt class="literal">nas default restriction</tt> will be ignored for alternate group specifications (e.g. <tt class="literal">member = group1/group2</tt>).</p>
</li>
<li>
<p><tt class="literal">tag</tt> ( <tt class="literal">acl</tt> [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">acl</i></span> ) <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>As described above, a user may manually select an (allowed) group profile at login time using the <tt class="literal">user*group</tt> syntax. You can override the user's choice using the <tt class="literal">tag</tt> directive in user or group profiles. Plus, you can make acl-based tag selections. E.g.:</p>
<pre class="screen">timespec = workinghours { "* 9-16 * * 1-5" "* 9-12 * * 6" }
timespec = weekend { "* * * * 6-1" }
timespec = changewindow { "* 22-23 * * Sat" "* 0-3 * * Sun" }

acl helpdesk = {
    time = workinghours
    nac = internal_lan
    nas = somecustomer
}

acl remoteadmin = {
    time = changewindow
    nac = dialin
}

user = fred {
    login = clear test
    member = admin/ro/emergency
    tag acl helpdesk = admin
    tag acl remoteadmin = emergency
    tag = ro
}</pre>
<p><tt class="literal">fred</tt> will be a member of the <tt class="literal">admin</tt> group during work hours, but only if his client IP address is part of the internal LAN and if he's on a certain NAS. He'll be member of the <tt class="literal">emergency</tt> group during change window hours, but needs to come from the dial-in pool. Outside these hours he's a member of the <tt class="literal">ro</tt> hours.</p>
<p><tt class="literal">tag</tt> definitions are evaluated in order. If no definition matches, the user's session tag (the group selected at login time using <tt class="literal">user*group</tt> syntax) is used. If no group tag was given, the first group in the <tt class="literal">member</tt> definition is selected.</p>
<p>In most cases, it might be a better idea to use <tt class="literal">member acl</tt> syntax instead of <tt class="literal">tag acl</tt>.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h6 class="section"><a name="AEN1818" id="AEN1818">4.3.8.3.6. Railroad Diagrams</a></h6>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/UserDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: UserDecl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/GroupDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: GroupDecl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/PasswordExpr.svg"></p>
<div class="caption">
<p>Railroad diagram: PasswordExpr</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/PasswordExprHash.svg"></p>
<div class="caption">
<p>Railroad diagram: PasswordExprHash</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/UserAttr.svg"></p>
<div class="caption">
<p>Railroad diagram: UserAttr</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/UserMessage.svg"></p>
<div class="caption">
<p>Railroad diagram: UserMessage</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/GroupAttr.svg"></p>
<div class="caption">
<p>Railroad diagram: GroupAttr</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/GroupOnlyAttr.svg"></p>
<div class="caption">
<p>Railroad diagram: GroupOnlyAttr</p>
</div>
</div>
</div>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1876" id="AEN1876">4.3.8.4. Service Restrictions</a></h5>
<ul>
<li>
<p><tt class="literal">default service =</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>This defines whether a service not explicitely defined in the user profile should be permitted or denied.</p>
</li>
<li>
<p><tt class="literal">prohibit service =</tt> <span class="emphasis"><i class="emphasis">service ...</i></span></p>
<p>Use this to override the default service specification. E.g., to explicitely deny the X.25 service:</p>
<pre class="screen">    prohibit service = x25</pre></li>
</ul>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN1891" id="AEN1891">4.3.8.5. Service Definitions</a></h5>
<p>Service definitions may appear in <span class="emphasis"><i class="emphasis">user</i></span> and <span class="emphasis"><i class="emphasis">group</i></span> sections. Services can easily be made dependent on ACLs:</p>
<p><tt class="literal">service</tt> ( <tt class="literal">acl</tt> [ <tt class="literal">not</tt> ] ACLName <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">service</i></span> <tt class="literal">{</tt> <span class="emphasis"><i class="emphasis">...</i></span> <tt class="literal">}</tt></p>
<p>There are a couple of generic configuration attributes which may appear in arbitrary service definitions. In particular:</p>
<ul>
<li>
<p><tt class="literal">default attribute =</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>This directive specifies whether the daemon is to accept or reject unknown attributes sent by the NAS (default: <tt class="literal">deny</tt>).</p>
</li>
<li>
<p><tt class="literal">acl =</tt> ( [ <tt class="literal">permit</tt> ] | <tt class="literal">deny</tt> ) [ <tt class="literal">not</tt> ] <span class="emphasis"><i class="emphasis">acl</i></span></p>
<p>Just as user and group profiles, services can be restricted by using ACLs.</p>
</li>
<li>
<p>( <tt class="literal">set</tt> | <tt class="literal">add</tt> | <tt class="literal">optional</tt> ) <span class="emphasis"><i class="emphasis">attribute</i></span> <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">value</i></span></p>
<p>Defines mandatory and optional attribute-value pairs:</p>
<ul>
<li>
<p><tt class="literal">set</tt> unconditionally returns a mandatory AV pair to the NAS</p>
</li>
<li>
<p><tt class="literal">optional</tt> returns a NAS-requested (and perhaps modified) optional AV pair to the NAS unless the attribute was already in the mandatory list</p>
</li>
<li>
<p><tt class="literal">add</tt> returns an optional AV pair to the client even if the client didn't request it (and it was neither in the mandatory nor optional list)</p>
</li>
</ul>
Example:
<pre class="screen">set priv-lvl = 15</pre>
<p>For a detailed description on mandatory and optional AV-pairs, see the "The Authorization Algorithm" section somewhere below.</p>
</li>
<li>
<p><tt class="literal">return</tt></p>
<p>Use the current service definition as-is. This stops the daemon from checking for the same service in the groups the current user (or group) is a member of.</p>
</li>
</ul>
<p>Other configuration attributes are service specific and only valid in certain contexts:</p>
<p><span class="bold"><b class="emphasis">SHELL (EXEC) Service</b></span></p>
<p>Shell startup should have an appropriate service</p>
<pre class="screen">service = shell { }</pre>
<p>defined. Valid configuration directive within the curly brackets are:</p>
<ul>
<li>
<p><tt class="literal">default cmd =</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> )</p>
<p>This directive specifies whether the daemon is to accept or reject commands not explicitely permitted (default: <tt class="literal">deny</tt>).</p>
</li>
<li>
<p><tt class="literal">message</tt> ( <tt class="literal">permit</tt> | <tt class="literal">deny</tt> ) <tt class="literal">=</tt> <span class="emphasis"><i class="emphasis">string</i></span></p>
<p>This specifies a message to be presented to the user on accepting or rejecting a command. Recognized string substitutions within <span class="emphasis"><i class="emphasis">string</i></span> are <tt class="literal">%c</tt> for the command name, <tt class="literal">%a</tt> for the command arguments and <tt class="literal">%C</tt> for the currenly set context. Example:</p>
<pre class="screen">message permit "Permitted '%c %a'"
message deny "Denied '%c %a'"</pre>
<p>This directive may appear in <tt class="literal">cmd</tt> sections, too, where it overrides the <tt class="literal">service</tt> section definitions.</p>
</li>
<li>
<p><tt class="literal">cmd =</tt> <span class="emphasis"><i class="emphasis">command</i></span> <tt class="literal">{</tt> ... <tt class="literal">}</tt></p>
<p><span class="emphasis"><i class="emphasis">cmd</i></span> sections permit or deny commands and command arguments. Example:</p>
<pre class="screen">cmd = show {
    deny /^(running|startup)-config/
    deny tech-support
    permit //
    message deny = "Try this again and your account will be revoked."
    message permit = "This data is to be considered confidentional."
}
cmd = reload {
    permit //
    message permit = "You hopefully know what you're doing ..."
}</pre>
<p>Regular expression syntax is POSIX or, if enabled at compile time, PCRE.</p>
</li>
</ul>
<p>If you're unsure what commands and arguments the router actually sends for verification, you may simply modify a user (or group) profile to display those within a login session. E.g.,</p>
<pre class="screen">user = ... {
    ...
    debug = CMD
    ...
    service = shell {
        ...
        message debug  = "author: 'cmd = %c { permit /^%a$/ }"
        ...
    }
}</pre>
<p>will display the configuration snippets to permit the command in PCRE syntax:</p>
<pre class="screen">Router#conf t
author: 'cmd = configure { permit /^terminal &lt;cr&gt;$/ }'

Enter configuration commands, one per line.  End with CNTL/Z.
Router(config)#</pre>
<p><span class="bold"><b class="emphasis">Non-Shell Services</b></span></p>
<p>E.g. for PPP, <span class="emphasis"><i class="emphasis">protocol</i></span> definitions may be used:</p>
<pre class="screen">service = ppp {
    protocol = ip { set addr = 1.2.3.4 }
}</pre>
<p>Use</p>
<pre class="screen">    default protocol = permit</pre>
<p>or</p>
<pre class="screen">    default protocol = deny</pre>
<p>to specify the default for protocols not explicitly defined within a service declaration. (default: <tt class="literal">deny</tt>).</p>
<p>For a Juniper Networks-specific authorization service, use:</p>
<pre class="screen">service = junos-exec {
   set local-user-name = NOC
   # see the Junos documentation for more attributes
}</pre>
<p>Likewise, for Raritan Dominion SX IP Console Servers:</p>
<pre class="screen">service = dominionsx {
    set port-list = "1 3 4 15"
    set user-type = administator # or operator, or observer
}</pre>
<div class="tip">
<table class="tip" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/tip.svg" hspace="5" alt="Tip"></td>
<th align="left" valign="middle"><b>Quotes</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>If your router expects double-quoted values (e.g. Cisco Nexus devices do), you can advise the parser to automatically add these:</p>
<pre class="screen">service = shell {
    set shell:roles="\"network-admin\""
}</pre>
<p>and</p>
<pre class="screen">service = shell {
    double-quote-values = yes
    set shell:roles="network-admin"
}</pre>
<p>are equivalent, but the latter is more readable.</p>
</td>
</tr>
</table>
</div>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2014" id="AEN2014">4.3.8.6. Host-group specific services</a></h5>
<p>Services can be configured NAS specific by appending <tt class="literal">@</tt><span class="emphasis"><i class="emphasis">host</i></span> to the service name. Here, <span class="emphasis"><i class="emphasis">host</i></span> is the name of a host object, <span class="bold"><b class="emphasis">not</b></span> an IP address or CIDR range. For example, a user's PPP address could be static on one particular NAS, but dynamic everywhere else:</p>
<pre class="screen">host = dialin { address = ... }
user = ... {
    service = ppp { protocol = ip { } }
    service = ppp@dialin { protocol = ip { set addr = 1.2.3.4 } }
}</pre>
<p>While the same can be achieved using host specific group membership, this adds some flexibility for dynamic authentication backends.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2023" id="AEN2023">4.3.8.7. CLI Contexts</a></h5>
<p>When used with <tt class="literal">single-connection</tt> and being told so, the daemon tries to remember command context. which permits the <tt class="literal">shutdown</tt> family of commands for exactly one interface, but denies it for all the others:</p>
<pre class="screen">
user = john {
    password = clear doe
    service = shell {
        default cmd = permit
        set priv-lvl = 15
        script = {
            if (cmd == "") permit # shell startup

            if (cmd =~ /^interface FastEthernet 0\/1 /) {
                message = "Context has been set. \"[no] shut\" should work for you."
                context = FE
                permit
            } else if (cmd =~ /^interface/){
                message = "Context has been reset."
                context = ""
                permit
            }
            if (context == FE) {
                if (cmd =~ /^shutdown/) permit
                if (cmd =~ /^no shutdown/) permit
                deny
            }
        }
        cmd = shutdown { deny . }
        cmd = no { deny /^shutdown/ }
    }       
}</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2029" id="AEN2029">4.3.8.8. Examples</a></h5>
<p>Here we declare two users <tt class="literal">fred</tt> and <tt class="literal">lily</tt>, and two groups, <tt class="literal">admin</tt> and <tt class="literal">staff</tt>.</p>
<p><tt class="literal">fred</tt> is a member of group <tt class="literal">admin</tt> and group <tt class="literal">admin</tt> is in turn a member of group <tt class="literal">staff</tt>. <tt class="literal">lily</tt> is not a member of any group.</p>
<pre class="screen">group = admin {
    # group admin is a member of group staff
    member = staff
    service = shell {
        set priv-lvl = 15
    }
}

group = staff {
    # group staff is not a member of any group
}

user = lily {
    # user lily is not a member of any group
    # and has nothing else configured as yet
}

user = fred {
    # fred is a member of group admin on 0.0.0.0/0
    member = admin
    # fred is a member of group staff when logging in on 10.0.0.0/8
    member = staff@10.0.0.0/8
    # fred is a member of group admin when logging in on hosts
    # defined in hostgroup test123
    member = admin@test123
    # fred may only log in from a client in 172.16.0.0/24 ...
    client = 172.16.0.0/24
    # ... or from whatever address is defined in some host object test123
    client = test123
}</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2043" id="AEN2043">4.3.8.9. Railroad Diagrams</a></h5>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ServiceDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: ServiceDecl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ServiceAttr.svg"></p>
<div class="caption">
<p>Railroad diagram: ServiceAttr</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/Acl.svg"></p>
<div class="caption">
<p>Railroad diagram: Acl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/AttrDefault.svg"></p>
<div class="caption">
<p>Railroad diagram: AttrDefault</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/AVPair.svg"></p>
<div class="caption">
<p>Railroad diagram: AVPair</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ShellDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: ShellDecl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ShellAttr.svg"></p>
<div class="caption">
<p>Railroad diagram: ShellAttr</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/TacScript.svg"></p>
<div class="caption">
<p>Railroad diagram: TacScript</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ShellCommandDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: ShellCommandDecl</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/CmdDefault.svg"></p>
<div class="caption">
<p>Railroad diagram: CmdDefault</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ProtoDefault.svg"></p>
<div class="caption">
<p>Railroad diagram: ProtoDefault</p>
</div>
</div>
<div class="mediaobject">
<p><img alt="" src="railroad/tac_plus/ProtoDecl.svg"></p>
<div class="caption">
<p>Railroad diagram: ProtoDecl</p>
</div>
</div>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2129" id="AEN2129">4.3.8.10. Configuring Non-local Users via MAVIS</a></h5>
<p><span class="bold"><b class="emphasis">MAVIS</b></span> configuration is optional. You don't need it if you're content with user configuration in the main configuration file.</p>
<p><span class="bold"><b class="emphasis">MAVIS</b></span> backends may dynamically create user entries, based, e.g., on LDAP information.</p>
<p>For PAP and LOGIN,</p>
<pre class="screen">pap backend = mavis
login backend = mavis</pre>
<p>in the global section delegate authentiation to the MAVIS sub-system. Statically defined users are still valid, and have a higher precedence.</p>
<p>By default, MAVIS user data will be cached for 120 seconds. You may change that period using</p>
<pre class="screen">cache timeout = <span class="emphasis"><i class="emphasis">seconds</i></span>
</pre>
<p>in the global configuration section.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2142" id="AEN2142">4.3.8.11. Configuring Local Users for MAVIS authentication</a></h5>
<p>Under certain circumstances you may wish to keep the user definitions in the plain text configuration file, but authenticate against some external system nevertheless, e.g. LDAP or RADIUS. To do so, just specify one of</p>
<pre class="screen">    login = mavis
    pap = mavis
    password = mavis</pre>
<p>in the corresponding user definition.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2147" id="AEN2147">4.3.8.12. Recursion and Groups</a></h5>
<p>In general, when the daemon looks up values, it will look first to see if the user has her own definition for that value. If not, it looks to see if she belongs to a group and if so, whether the group has a value defined. If not, this process continues through the hierarchy of groups (a group can be a member of another group) until a value is found, or there are no more gmaryroups.</p>
<p>This recursive process occurs for lookups of expiration dates and also for authorization parameters (see later), but not for user passwords.</p>
<p>A typical configuration technique is thus to place users into groups and specify as many groupwide characteristics in the group declaration as possible. Then, individual user declarations can be used to override the group settings for selected users as needed.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2152" id="AEN2152">4.3.8.13. Configuring User Authentication</a></h5>
<p>User Authentication can be specified separately for PAP, ARAP, CHAP, and normal logins. ARAP, CHAP, and global user authentication must be given in clear text.</p>
<p>The following assigns the user mary five different passwords for ARAP, inbound and outbound CHAP, inbound PAP, outbound PAP, and normal login respectively:</p>
<pre class="screen">user = mary {
    arap = clear "arap password"
    chap = clear "chap password"
    pap  = clear "inbound pap password"
    login = crypt XQj4892fjk
}</pre>
<p>If</p>
<pre class="screen">user backend = mavis</pre>
<p>is configured in the global section, users not found in the configuration file will be looked up by the MAVIS backend. You should consider using this option in conjuction with the more sophisticated backends (LDAP and ActiveDirectory, in particular), or whenever you're not willing to duplicate your pre-existing database user data to the configuration file. For users looked up by the MAVIS backend,</p>
<pre class="screen">pap backend = mavis</pre>
<p>and/or</p>
<pre class="screen">login backend = mavis</pre>
<p>(again, in the global section of the configuration file) will cause PAP and/or Login authentication to be performed by the MAVIS backend (e.g. by performing an LDAP bind), ignoring any corresponding password definitions in the users' profile.</p>
<p>If you just want the users defined in your configuration file to authenticate using the MAVIS backend, simply set the corresponding PAP or Login password field to <tt class="literal">mavis</tt> (there's no need to add the <tt class="literal">user backend = mavis</tt> directive in this case):</p>
<pre class="screen">user = mary { login = mavis }</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2168" id="AEN2168">4.3.8.14. Configuring Expiry Dates</a></h5>
<p>An entry of the form:</p>
<pre class="screen">user = lol {
    valid until = <span class="emphasis"><i class="emphasis">YYYY</i></span>-<span class="emphasis"><i class="emphasis">MM</i></span>-<span class="emphasis"><i class="emphasis">DD</i></span>
    login = clear "bite me"
}</pre>
<p>will cause the profile to become invalid, starting after the <tt class="literal">valid until</tt> date. Valid date formats are both ISO8601 and the absolute number of seconds since 1970-01-01.</p>
<p>A expiry warning message is sent to the user when she logs in, by default starting at 14 days before the expiration date, but configurable via the <tt class="literal">warning period</tt> directive.</p>
<p>Complementary to profile expiry,</p>
<pre class="screen">    valid from = <span class="emphasis"><i class="emphasis">YYYY</i></span>-<span class="emphasis"><i class="emphasis">MM</i></span>-<span class="emphasis"><i class="emphasis">DD</i></span></pre>
<p>activates a profile at the given date.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2185" id="AEN2185">4.3.8.15. Configuring Authentication on the NAS</a></h5>
<p>On the NAS, to configure login authentication, try</p>
<pre class="screen">aaa new-model
aaa authentication login default group tacacs+ local</pre>
<p>(Alternatively, you can try a <span class="emphasis"><i class="emphasis">named authentication list</i></span> instead of <tt class="literal">default</tt>. Please see the IOS documentation for details.)</p>
<div class="caution">
<table class="caution" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/caution.svg" hspace="5" alt="Caution"></td>
<th align="left" valign="middle"><b>Don't lock yourself out.</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>As soon as you issue this command, you will no longer be able to create new logins to your NAS without a functioning TACACS+ daemon appropriately configured with usernames and password, so make sure you have this ready.</p>
<p>As a safety measure while setting up, you should configure an enable secret and make it the last resort authentication method, so if your TACACS+ daemon fails to respond you will be able to use the NAS enable password to login. To do this, configure:</p>
<pre class="screen">aaa authentication login default group tacacs+ enable</pre>
<p>or, to if you have local accounts:</p>
<pre class="screen">aaa authentication login default group tacacs+ local</pre>
<p>If all else fails, and you find yourself locked out of the NAS due to a configuration problem, the section on <span class="emphasis"><i class="emphasis">recovering from lost passwords</i></span> on Cisco's CCO web page will help you dig your way out.</p>
</td>
</tr>
</table>
</div>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2201" id="AEN2201">4.3.8.16. Configuring Authorization</a></h5>
<p>Authorization must be configured on both the NAS and the daemon to operate correctly. By default, the NAS will allow everything until you configure it to make authorization requests to the daemon.</p>
<p>On the daemon, the opposite is true: The daemon will, by default, deny authorization of anything that isn't explicitly permitted.</p>
<p>Authorization allows the daemon to deny commands and services outright, or to modify commands and services on a per-user basis. Authorization on the daemon is divided into two separate parts: commands and services.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2206" id="AEN2206">4.3.8.17. Authorizing Commands</a></h5>
<p>Exec commands are those commands which are typed at a Cisco exec prompt. When authorization is requested by the NAS, the entire command is sent to the tac_plus daemon for authorization.</p>
<p>Command authorization is configured by specifying a list of PCRE (Perl Compatible Regular Expressions) or <tt class="literal">egrep</tt>-style (POSIX 1003.2) regular expressions to match command arguments (see your local <tt class="literal">pcrematching</tt><span class="emphasis"><i class="emphasis">(3)</i></span> or <tt class="literal">regex</tt><span class="emphasis"><i class="emphasis">(7)</i></span> man page, respectively, for a description of regular expressions), and an action which is <tt class="literal">deny</tt> or <tt class="literal">permit</tt>.</p>
<div class="tip">
<table class="tip" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/tip.svg" hspace="5" alt="Tip"></td>
<th align="left" valign="middle"><b>Case-insensitive pattern-matching</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>By default, regular expression matching is <span class="emphasis"><i class="emphasis">case-insensitive</i></span>. This can be changed by specifying</p>
<pre class="screen">regex-match-case = yes</pre></td>
</tr>
</table>
</div>
<p>If a POSIX pattern contains spaces or special characters, you'll have to enclose the pattern in double quotes (<tt class="literal">"</tt>). For text inside double quotes, C parsing rules apply. In particular, the backslash <tt class="literal">\</tt> needs to be escaped as <tt class="literal">\\</tt>. PCRE patterns need to be enclosed in slashes (<tt class="literal">/</tt><span class="emphasis"><i class="emphasis">pattern</i></span><tt class="literal">/</tt>). Both POSIX and PCRE syntax may be used in the same configuration file.</p>
<p>The following configuration example permits user Fred to run the following commands:</p>
<pre class="screen">telnet 131.108.13.<span class="emphasis"><i class="emphasis">any_number</i></span>
telnet 128.<span class="emphasis"><i class="emphasis">any_number</i></span>.12.3
show running-config interface <span class="emphasis"><i class="emphasis">anything</i></span> </pre>
<p>All other commands are denied (by default).</p>
<pre class="screen">user=fred {
    # default service = deny
    service = shell { 
        # default cmd = deny
        cmd = telnet {
            # permit specified telnets
            # POSIX:
            permit ^131\.108\.13\.[0-9]+$
            # PCRE:
            permit /^128\.\d+\.12\.3$/
        }
        cmd = show {
            # permit show commands
            # PCRE:
            permit /^running-config interface/
        }
    }
}</pre>
<div class="tip">
<table class="tip" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/tip.svg" hspace="5" alt="Tip"></td>
<th align="left" valign="middle"><b>Whitespace</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>If any non-PCRE argument list you specify contains spaces or tabs, you must enclose it in double quotes. PCRE expressions are to be enclosed in slashes, anyway.</p>
</td>
</tr>
</table>
</div>
<p>The command and arguments which the user types gets matched to the regular expressions you specify in the configuration file (in order of appearance). The first successful match performs the associated action (permit or deny). If there is no match, the command is denied by default.</p>
<p>Conversely, the following configuration example can be used to deny the command:</p>
<pre class="screen">telnet 131.108.13.<span class="emphasis"><i class="emphasis">any_number</i></span> </pre>
<p>and permit all other arguments, since the last line will match any argument list. All other commands and services are permitted due to the "default service = permit" clause.</p>
<p>Note: the default statement must be the first in the user clause</p>
<pre class="screen">user=fred {
    default service = permit
    service = shell {
        cmd = telnet {
            # allow all telnet commands except to 131.108.13.*
            deny ^131\.108\.13\.[0-9]+
            permit .*
        }
    }
}</pre>
<p>Matches are only anchored if you specify so, so <tt class="literal">deny 131.108.13.[0-9]+</tt> matches anywhere in the command. To anchor the match, use <tt class="literal">^</tt> at the beginning of the regular expression.</p>
<p>When a command has multiple arguments, users may enter them in many different permutations. It can be cumbersome to create regular expressions which will reliably authorize commands under these conditions, so administrators may wish to consider other methods of performing authorization e.g. by configuring NAS-local privileged enable levels on the NAS itself.</p>
<div class="section">
<hr>
<h6 class="section"><a name="AEN2250" id="AEN2250">4.3.8.17.1. Command Expansion</a></h6>
<p>For command authorization, the Cisco NAS expands all commands to their full names e.g. when you type <tt class="literal">config t</tt> on the NAS, this will be expanded to <tt class="literal">configuration terminal</tt> before being sent to the daemon so that you don't need to list all the possible contractions of a command.</p>
<p>At the user level i.e. inside the braces of a user declaration, the default for a user who doesn't have a service or command explicitly authorized is to deny that service or command. The following directive will permit the service or command by default instead:</p>
<pre class="screen">user = lol {
    default service = permit
}</pre>
<p><span class="emphasis"><i class="emphasis">Note:</i></span> This directive must appear first inside the user declaration.</p>
<p>At the service authorization level i.e. inside the braces of a service declaration, arguments in an authorization request are processed according to the algorithm described later. Some actions when authorizing services (e.g. when matching attributes are not found) depend on how the default is configured. The following declaration changes the default from deny to permit for this user and service.</p>
<pre class="screen">user = lol { service = shell { default attribute = permit } }</pre>
<p><span class="emphasis"><i class="emphasis">Note:</i></span> This directive must appear before any others inside the service declaration.</p>
<p><span class="emphasis"><i class="emphasis">Note:</i></span> for command authorization (as opposed to service authorization being discussed here), you specify deny .* or permit .* as the last line of the regular expression matches to create default behavior.</p>
</div>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2265" id="AEN2265">4.3.8.18. Authorizing EXEC (SHELL) Startup</a></h5>
<p>You can supply some parameters whenever an shell starts, e.g. an autocommand, a dialback string or a connection access list (acl). In the example below, when an exec is started on the NAS, an acl of 4 will be returned to the NAS:</p>
<pre class="screen">user=fred {

    # this following line permits an exec to start and permits
    # all commands and services by default

    default service = permit

    service = shell {
        # When an exec is started, its connection access list will be 4.
        # It also has an autocmd.
        set acl = 4
        set autocmd = "telnet foobar"

        cmd = telnet {
            # allow all fred's telnet commands except telnet to 131.108.13.*
            deny 131\.108\.13\.[0-9]+
            permit .*
        }
    }
}</pre>
<p><span class="emphasis"><i class="emphasis">Note:</i></span> specifying an autocommand, or any other exec services, is part of EXEC AUTHORIZATION. For it to work, you must also configure exec authorization on your NAS e.g.</p>
<pre class="screen">aaa authorization exec authorlist group tacacs+ local
aaa authorization commands 15 cmdlist group tacacs+ local</pre>
<p>and, eventually, on the lines:</p>
<pre class="screen">authorization commands 15 cmdlist
authorization exec authorlist</pre>
<p>Just as with authentication, you can use a <span class="emphasis"><i class="emphasis">named authorization list</i></span>, or simply <tt class="literal">default</tt>.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2277" id="AEN2277">4.3.8.19. Authorizing EXEC, SLIP, PPP and ARAP services</a></h5>
<p>Authorizing EXEC, SLIP, PPP and ARAP services is done quite differently from command authorization.</p>
<p>When authorizing these services, the NAS sends a request containing a number of attribute-value (AV) pairs, each having the form</p>
<pre class="screen">attribute=value</pre>
<p>(Note: during debugging, you may see AV pairs whose separator character is a <tt class="literal">*</tt> instead of a <tt class="literal">=</tt> sign, meaning that the value in a pair is optional. An <tt class="literal">=</tt> sign indicates a mandatory value. A <tt class="literal">*</tt> denotes an optional value).</p>
<p>E.g., a user starting PPP/IP using an address of <tt class="literal">131.108.12.44</tt> would generate a request with the following AV pairs:</p>
<pre class="screen">service=ppp
protocol=ip
addr*131.108.12.44</pre>
<p>You can use the NAS debugging command</p>
<pre class="screen">debug aaa authorization</pre>
<p>to see what authorization AV pairs are being used by the NAS. Note: If you are not on the router console, you will also need to issue a <tt class="literal">terminal monitor</tt> command to see debug output.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2294" id="AEN2294">4.3.8.20. The Authorization Process</a></h5>
<p>Authorizing a single session can result in multiple requests being sent to the daemon. For example, in order to authorize a dialin PPP user for IP, the following authorization requests will be made from the NAS:</p>
<ol type="1">
<li>
<p>An initial authorization request to startup PPP from the exec, using the AV pairs <tt class="literal">service=ppp</tt>, <tt class="literal">protocol=ip</tt>, will be made (Note: this initial request will be omitted if you are autoselecting PPP, since you won't know the username yet).</p>
<p>This request is really done to find the address for dumb PPP (or SLIP) clients who can't do address negotiation. Instead, they expect you to tell them what address to use before PPP starts up, via a text message e.g. "Entering PPP. Your address is 1.2.3.4". They rely on parsing this address from the message to know their address.</p>
</li>
<li>
<p>Next, an authorization request is made from the PPP subsystem to see if PPP's LCP layer is authorized. LCP parameters can be set at this time (e.g. callback). This request contains the AV pairs <tt class="literal">service=ppp</tt>, <tt class="literal">protocol=lcp</tt>.</p>
</li>
<li>
<p>Next an authorization request to startup PPP's IPCP layer is made using the AV pairs <tt class="literal">service=ppp</tt>, <tt class="literal">protocol=ipcp</tt>. Any parameters returned by the daemon are cached.</p>
</li>
<li>
<p>Next, during PPP's address negotiation phase, each time the remote peer requests a specific address, if that address isn't in the cache obtained in step 3, a new authorization request is made to see if the peers requested address is allowable. This step can be repeated multiple times until both sides agree on the remote peer's address or until the NAS (or client) decide they're never going to agree and they shut down PPP instead.</p>
</li>
</ol>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2313" id="AEN2313">4.3.8.21. Authorization Relies on Authentication</a></h5>
<p>Since we pretty much rely on having a username in authorization requests to decide which addresses etc. to hand out, it is important to know where the username for a PPP user comes from. There are generally 2 possible sources:</p>
<ol type="1">
<li>
<p>You force the user to authenticate by making her login to the exec and you use that login name in authorization requests. This username isn't propagated to PPP by default. To have this happen, you generally need to configure the <tt class="literal">if-needed</tt> method, e.g.</p>
<pre class="screen">aaa authentication login default tacacs+
aaa authentication ppp default if-needed</pre></li>
<li>
<p>Alternatively, you can run an authentication protocol, PAP or CHAP (CHAP is much preferred), to identify the user. You don't need an explicit login step if you do this (so it's the only possibility if you are using autoselect). This authentication gets done before you see the first LCP authorization request of course. Typically you configure this by doing:</p>
<pre class="screen">aaa authentication ppp default tacacs+ 
int async 1
  ppp authentication chap</pre></li>
</ol>
<p>If you omit either of these authentication schemes, you will start to see authorization requests in which the username is missing.</p>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2325" id="AEN2325">4.3.8.22. Configuring Service Authorization</a></h5>
<p>A list of AV pairs is placed in the daemon's configuration file in order to authorize services. The daemon compares each NAS AV pair to its configured AV pairs and either allows or denies the service. If the service is allowed, the daemon may add, change or delete AV pairs before returning them to the NAS, thereby restricting what the user is permitted to do.</p>
<div class="section">
<hr>
<h6 class="section"><a name="AEN2328" id="AEN2328">4.3.8.22.1. The Authorization Algorithm</a></h6>
<p>The complete algorithm by which the daemon processes its configured AV pairs against the list the NAS sends, is given below.</p>
<p>Find the user (or group) entry for this service (and protocol), then for each AV pair sent from the NAS:</p>
<ol type="1">
<li>
<p>If the AV pair from the NAS is mandatory:</p>
<ol type="a">
<li>
<p>look for an exact attribute,value match in the user's mandatory list. If found, add the AV pair to the output.</p>
</li>
<li>
<p>If an exact match doesn't exist, look in the user's optional list for the first attribute match. If found, add the NAS AV pair to the output.</p>
</li>
<li>
<p>If no attribute match exists, deny the command if the default is to deny, or,</p>
</li>
<li>
<p>If the default is permit, add the NAS AV pair to the output.</p>
</li>
</ol>
</li>
<li>
<p>If the AV pair from the NAS is optional:</p>
<ol type="a">
<li>
<p>look for an exact attribute,value match in the user's mandatory list. If found, add DAEMON's AV pair to output.</p>
</li>
<li>
<p>If not found, look for the first attribute match in the user's mandatory list. If found, add DAEMON's AV pair to output.</p>
</li>
<li>
<p>If no mandatory match exists, look for an exact attribute,value pair match among the daemon's optional AV pairs. If found add the DAEMON's matching AV pair to the output.</p>
</li>
<li>
<p>If no exact match exists, locate the first attribute match among the daemon's optional AV pairs. If found add the DAEMON's matching AV pair to the output.</p>
</li>
<li>
<p>If no match is found, delete the AV pair if the default is deny, or</p>
</li>
<li>
<p>If the default is permit add the NAS AV pair to the output.</p>
</li>
</ol>
</li>
<li>
<p>After all AV pairs have been processed, for each mandatory DAEMON AV pair, if there is no attribute match already in the output list, add the AV pair (but add only ONE AV pair for each mandatory attribute).</p>
</li>
<li>
<p>After all AV pairs have been processed, for each optional unrequested DAEMON AV pair, if there is no attribute match already in the output list, add that AV pair (but add only ONE AV pair for each optional attribute).</p>
</li>
</ol>
</div>
<div class="section">
<hr>
<h6 class="section"><a name="AEN2363" id="AEN2363">4.3.8.22.2. Recursive Authorization</a></h6>
<p>Remember that authorization is also recursive over groups. Thus, if you place a user in a group, the daemon will look in the group for authorization parameters if it cannot find them in the user declaration.</p>
</div>
</div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2366" id="AEN2366">4.3.8.23. Examples</a></h5>
<pre class="screen">host = 0.0.0.0/0 {
    key = "your key here"
}

group = admin {
    # group members who have no expiry date set will use this one
    valid until = 1997-01-01
    service = shell {
        default cmd = permit
    }
}

user=fred {
    login = crypt mEX027bHtzTlQ
    member = admin
    valid until = 2005-05-23

    service = shell {
        # When Fred starts an exec, his connection access list is 5
        set acl = 5

        # We require this autocmd to be done at startup
        set autocmd = "telnet foo"

        # All commands except show system are denied for Fred
        cmd = show {
            # Fred can run the following show command
            permit system
            deny .
        }
    }

    service = ppp {
        protocol = lcp
        protocol = ip {
            # Fred can run IP over PPP only if he uses one
            # of the following mandatory addresses. If he
            # supplies no address, the first one here will
            # be mandated
            set addr=131.108.12.11
            set addr=131.108.12.12
            set addr=131.108.12.13
            set addr=131.108.12.14

            # Fred's mandatory input access list number is 101
            set inacl=101

            # We will suggest an output access list of 102,
            # but the NAS may choose to ignore or override it
            optional outacl=102
        }
    }

    service = slip {
        default protocol = permit
        # Fred can run SLIP. When he does, he will have to use
        # these mandatory access lists
        set inacl=101
        set outacl=102
    }
}

user = wilma {
    login = crypt mEX027bHtzTlQ
    member = admin
}</pre></div>
<div class="section">
<hr>
<h5 class="section"><a name="AEN2370" id="AEN2370">4.3.8.24. Configuring Authorization on the NAS</a></h5>
<p>If authorization is not explicitly configured on the NAS, no authorization takes place, i.e. effectively, everything is permitted. Note that this is the converse of what happens on the daemon, where anything not explicitly permitted is denied by default.</p>
<p>To configure command authorization on the NAS, issue the following NAS configuration commands:</p>
<pre class="screen">aaa authorization commands 15 cmdlist group tacacs+ local</pre>
<p>and, on the lines:</p>
<pre class="screen">aaa authorization commands 1 cmdlist
aaa authorization commands 15 cmdlist</pre>
<p>This will make the NAS send TACACS+ requests for all level 1 (ordinary user) and level 15 (privileged level) commands.</p>
<p><span class="emphasis"><i class="emphasis">Note:</i></span> As soon as you configure the above on your NAS, you will only be permitted to execute NAS commands which are permitted by your TACACS+ daemon. So make sure you have configured, on the daemon, an authenticated user who is authorized to run commands, or you will be unable to do much on the NAS after turning on authorization.</p>
<p>Alternatively, or in addition, you may also want to configure the following:</p>
<pre class="screen">aaa authorization commands 1 group tacacs+ if-authenticated</pre>
<p>This will use TACACS+ authorization for level 1 (user-level commands) but if problems arise, you can just switch off the TACACS+ server and authorization will then be granted to anyone who is authenticated.</p>
<p>The following daemon configuration should be sufficient to ensure that you can always login as username <tt class="literal">admin</tt> (with a suitable password) and run any command as that user:</p>
<pre class="screen">user = admin {
    default service = permit
    service = shell { default cmd = permit }
    login = crypt kppPfHq/j6gXs
}</pre></div>
</div>
</div>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN2386" id="AEN2386">5. MAVIS Backends</a></h2>
<p>The distribution comes with various <span class="emphasis"><i class="emphasis">MAVIS</i></span> modules, of which the <span class="emphasis"><i class="emphasis">external</i></span> module is probably the most interesting, as it interacts with simple Perl scripts to authenticate and authorize requests. You'll find sample scripts in the <tt class="literal">mavis/perl</tt> directory. Have a close look at them, as you may (or will) need to perform some trivial customizations to make them match your local environment.</p>
<p>You should really have a look at the <span class="emphasis"><i class="emphasis">MAVIS</i></span> documentation. It gives examples for RADIUS and PAM authentication, too.</p>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2394" id="AEN2394">5.1. LDAP Backends</a></h3>
<p><tt class="literal">mavis_tacplus_ldap.pl</tt> is an authentication/authorization backend for the <span class="emphasis"><i class="emphasis">external</i></span> module. It interfaces to various kinds of LDAP servers, e.g. OpenLDAP, Fedora DS and Active Directory. Its behaviour is controlled by a list of environmental variables:</p>
<div class="informaltable"><a name="AEN2399" id="AEN2399"></a>
<table border="1" frame="border" class="CALSTABLE">
<col width="30%" title="col1">
<col width="70%" title="col2">
<thead>
<tr>
<th>Variable</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><tt class="literal">LDAP_SERVER_TYPE</tt></td>
<td>
<p>One of: <tt class="literal">generic</tt>, <tt class="literal">tacacs_schema</tt>, <tt class="literal">microsoft</tt>.</p>
<p>Default: <tt class="literal">tacacs_schema</tt></p>
</td>
</tr>
<tr>
<td><tt class="literal">LDAP_HOSTS</tt></td>
<td>
<p>Space-separated list of LDAP URLs or IP addresses or hostnames</p>
<p>Examples:</p>
<p><tt class="literal">"ldap01 ldap02"</tt>, <tt class="literal">"ldaps://ads01:636 ldaps://ads02:636"</tt></p>
</td>
</tr>
<tr>
<td><tt class="literal">LDAP_SCOPE</tt></td>
<td>
<p>LDAP search scope (<tt class="literal">base</tt>, <tt class="literal">one</tt>, <tt class="literal">sub</tt>)</p>
<p>Default: <tt class="literal">sub</tt></p>
</td>
</tr>
<tr>
<td><tt class="literal">LDAP_BASE</tt></td>
<td>
<p>Base DN of your LDAP server</p>
<p>Example: <tt class="literal">dc=example,dc=com</tt></p>
</td>
</tr>
<tr>
<td><tt class="literal">LDAP_FILTER</tt></td>
<td>
<p>LDAP search filter. Defaults:</p>
<ul>
<li>
<p>for <tt class="literal">LDAP_SERVER_TYPE=generic</tt>:</p>
<p><tt class="literal">"(uid=%s)"</tt></p>
</li>
<li>
<p>for <tt class="literal">LDAP_SERVER_TYPE=tacacs_schema</tt>:</p>
<p><tt class="literal">"(&amp;(uid=%s)(objectClass=tacacsAccount))"</tt></p>
</li>
<li>
<p>for <tt class="literal">LDAP_SERVER_TYPE=microsoft</tt>:</p>
<p><tt class="literal">"(&amp;(objectclass=user)(sAMAccountName=%s))"</tt></p>
</li>
</ul>
</td>
</tr>
<tr>
<td><tt class="literal">LDAP_FILTER_CHPW</tt></td>
<td>
<p>LDAP search filter for password changes. Defaults:</p>
<ul>
<li>
<p>for <tt class="literal">LDAP_SERVER_TYPE=generic</tt>:</p>
<p><tt class="literal">"(uid=%s)"</tt></p>
</li>
<li>
<p>for <tt class="literal">LDAP_SERVER_TYPE=tacacs_schema</tt>:</p>
<p><tt class="literal">"(&amp;(uid=%s)(objectClass=tacacsAccount)(!(tacacsFlag=staticpasswd)))"</tt></p>
</li>
<li>
<p>for <tt class="literal">LDAP_SERVER_TYPE=microsoft</tt>:</p>
<p><tt class="literal">"(&amp;(objectclass=user)(sAMAccountName=%s))"</tt></p>
</li>
</ul>
</td>
</tr>
<tr>
<td><tt class="literal">LDAP_USER</tt></td>
<td>
<p>User to use for LDAP bind if server doesn't permit anonymous searches.</p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">LDAP_PASSWD</tt></td>
<td>
<p>Password for <tt class="literal">LDAP_USER</tt></p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">AD_GROUP_PREFIX</tt></td>
<td>
<p>An AD group starting with this prefix will be used as the user's TACACS+ group membership. The value of <tt class="literal">AD_GROUP_PREFIX</tt> will be stripped from the group name.</p>
<p>Example: With <tt class="literal">AD_GROUP_PREFIX</tt> set to <tt class="literal">tacacs</tt> (which is actually the default), an AD group membership of <tt class="literal">TacacsNOC</tt> will assign the user to the <tt class="literal">NOC</tt> TACACS+ group. Note that TACACS+ group names are case-sensitive.</p>
</td>
</tr>
<tr>
<td><tt class="literal">REQUIRE_AD_GROUP_PREFIX</tt></td>
<td>
<p>If set, user needs to be in one of the <tt class="literal">AD_GROUP_PREFIX</tt> groups.</p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">USE_TLS</tt></td>
<td>
<p>If set, the server is required to support <tt class="literal">start_tls</tt>.</p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">FLAG_CHPW</tt></td>
<td>
<p>Permit password changes via this backend.</p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">FLAG_PWPOLICY</tt></td>
<td>
<p>Try to enforce a simplicistic password policy.</p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">FLAG_CACHE_CONNECTION</tt></td>
<td>
<p>Keep connection to LDAP server open.</p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">FLAG_FALLTHROUGH</tt></td>
<td>
<p>If searching for the user in LDAP fails, try the next MAVIS module (if any).</p>
<p>Default: unset</p>
</td>
</tr>
<tr>
<td><tt class="literal">FLAG_USE_MEMBEROF</tt></td>
<td>
<p>Use the <tt class="literal">memberOf</tt> attribute for determining group membership. Setting <tt class="literal">LDAP_SERVER_TYPE</tt> to <tt class="literal">microsoft</tt> implies this. May be used if you're running <span class="emphasis"><i class="emphasis">OpenLDAP</i></span> with <span class="bold"><b class="emphasis">memberof</b></span> overlay enabled.</p>
<p>Default: unset</p>
</td>
</tr>
</tbody>
</table>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN2559" id="AEN2559">5.1.1. LDAP Custom Schema Backend</a></h4>
<p>For <tt class="literal">LDAP_SERVER_TYPE</tt> set to <tt class="literal">tacacs_schema</tt>, the program expects the LDAP server to support the experimental <tt class="literal">ldap.schema</tt>, included for OpenLDAP and Fedora-DS. The schema files are located in the <tt class="literal">mavis/perl</tt> directory.</p>
<p>The new schema allows for a <span class="emphasis"><i class="emphasis">auxiliary</i></span> object class</p>
<pre class="screen">objectClass: tacacsAccount</pre>
<p>which introduces a couple of new attributes. A sample user entry could then look similar to the following LDIF snippet:</p>
<pre class="screen">dn: uid=marc,ou=people,dc=example,dc=com
uid: marc
cn: Marc Huber
objectClass: posixAccount
objectClass: inetOrgPerson
objectClass: shadowAccount
<span class="bold"><b class="emphasis">objectClass: tacacsAccount</b></span>
shadowMax: 10000
uidNumber: 1000
gecos: Marc Huber
givenName: Marc
sn: Huber
gidNumber: 500
shadowLastChange: 14012
loginShell: /bin/bash
homeDirectory: /Users/marc
mail: marc@example.com
userPassword:: abcdefghijklmnopqrstuvwxyz=
<span class="bold"><b class="emphasis">tacacsClient: 192.168.0.0/24
tacacsClient: management
tacacsMember: readonly@172.16.5.0/24
tacacsMember: readwrite@nasgroup
tacacsProfile: { valid until = 2010-01-30 chap = clear ahzoi5Ue }</b></span>
</pre>
<p>As <tt class="literal">tacacsProfile</tt> may (and most probably will) contain sensitive data, you should consider setting up LDAP ACLs to restrict access.</p>
<p>You should be pretty familiar with OpenLDAP (or, for that matter, Fedora-DS) if you're willing to go this route. For current versions of OpenLDAP: Use <tt class="literal">ldapadd</tt> to add <tt class="literal">tacacs_schema.ldif</tt> to the <tt class="literal">cn=config</tt> tree. For older versions, add <tt class="literal">tacacs.schema</tt> to the list of <tt class="literal">include</tt>d schema and objectClass definitions in <tt class="literal">slapd.conf</tt>.</p>
</div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN2582" id="AEN2582">5.1.2. Active Directory Backend</a></h4>
<p>If <tt class="literal">LDAP_SERVER_TYPE</tt> is set to <tt class="literal">microsoft</tt>, the script backends to AD servers. Sample configuration:</p>
<pre class="screen">id = spawnd {
    listen = {
        port = 49
    }
    spawn = {
        instances min = 1
        instances max = 10
    }
    background = yes
}

id = tac_plus {
    access log = /var/log/tacacs/%Y/%m/%d/access.log
    accounting log = /var/log/tacacs/%Y/%m/%d/acct.log

    mavis module = external {
        # Optionally:
        # script out = {
        #     # Require group membership:
        #     if (undef($TACMEMBER) &amp;&amp; $RESULT == ACK) set $RESULT = NAK
        #
        #     # Don't cache passwords:
        #     if ($RESULT == ACK) set $PASSWORD_ONESHOT = 1
        # }

        setenv LDAP_SERVER_TYPE = "microsoft"
        # setenv LDAP_HOSTS = "ldaps://ads01:636 ldaps://ads02:636"
        setenv LDAP_HOSTS = "ads01:3268 ads02:3268"
        setenv LDAP_SCOPE = sub
        setenv LDAP_BASE = "dc=example,dc=com"
        setenv LDAP_FILTER = "(&amp;(objectclass=user)(sAMAccountName=%s))";
        setenv LDAP_USER = tacacs@example.com
        setenv LDAP_PASSWD = Secret123
        setenv AD_GROUP_PREFIX = tacacs
        # setenv REQUIRE_AD_GROUP_PREFIX = 1
        setenv USE_TLS = 0
        exec = /usr/local/lib/mavis/mavis_tacplus_ldap.pl
    }

    login backend = mavis
    pap backend = mavis

    host = world {
        address = ::/0
        welcome banner = "Welcome\n"
        key = cisco
    }

    host = helpdesklab {
        address = 192.168.34.16/28
    }

    # A user will be in the "admin" group if he's member of the
    # corresponding "tacacsadmin" ADS group.

    group = admin {
        default service = permit
        service = shell {
            default command = permit
            default attribute = permit
            set priv-lvl = 15
        }
    }

    # A user will be in the "helpdesk" group if he's member of the
    # corresponding "tacacshelpdesk" ADS group:

    group = helpdesk {
        default service = permit
        service = shell {
            default command = permit
            default attribute = permit
            set priv-lvl = 1
        }
        enable = deny
        member = admin@helpdesklab
    }
}</pre></div>
<div class="section">
<hr>
<h4 class="section"><a name="AEN2588" id="AEN2588">5.1.3. Generic LDAP Backend</a></h4>
<p>If <tt class="literal">LDAP_SERVER_TYPE</tt> is set to <tt class="literal">generic</tt>, the script won't require any modification to your LDAP server, but only authenticates users (with <tt class="literal">login = mavis</tt>, <tt class="literal">pap = mavis</tt> or <tt class="literal">password = mavis</tt> declaration) defined in the configuration file. No authorization is done by this backend.</p>
</div>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2596" id="AEN2596">5.2. PAM backend</a></h3>
<p>Example configuration for using <span class="emphasis"><i class="emphasis">Pluggable Authentication Modules</i></span>:</p>
<pre class="screen">id = spawnd { listen = { port = 49 } }

id = tac_plus {
  mavis module = groups {
    resolve gids = yes
    groups filter = /^(guest|staff)$/
    script out = {
      # copy the already filtered UNIX group access list to TACMEMBER
      eval $GIDS =~ /^(.*)$/
      set $TACMEMBER = $1
    }
  }
  mavis module = external {
    exec = /usr/local/sbin/pammavis pammavis "-s" "sshd"
  }
  user backend = mavis
  login backend = mavis
  host = global { address = 0.0.0.0/0 key = cisco }

  group = staff {
    service = shell {
      default command = permit
      set priv-lvl = 15
    }
  }
  group = guest {
    service = shell {
      default command = deny
      set priv-lvl = 15
      cmd = show { permit .* }
    }
  }
}</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2601" id="AEN2601">5.3. System Password Backends</a></h3>
<p><tt class="literal">mavis_tacplus_passwd.pl</tt> authenticates against your local password database. Alas, to use this functionality, the script may have to run as root, as it needs access to the encrypted passwords. Primary and auxiliary UNIX group memberships will be mapped to TACACS+ groups.</p>
<p><tt class="literal">mavis_tacplus_opie.pl</tt> is based on <tt class="literal">mavis_tacplus_passwd.pl</tt>, but uses OPIE one-time passwords for authentication.</p>
<pre class="screen">id = spawnd {
  listen = { port = 49 }
}

id = tac_plus {
  mavis module = external {
    exec = /usr/local/lib/mavis/mavis_tacplus_opie.pl
  }
  login backend = mavis chalresp
  host = global { address = 0.0.0.0/0 key = cisco }
  group = staff {
    service = shell {
      default command = permit
      set priv-lvl = 15
    }
  }
  user = user1 { password = mavis member = staff }
  user = user2 { password = clear pass2 member = staff }
}</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2609" id="AEN2609">5.4. Shadow Backend</a></h3>
<p><tt class="literal">mavis_tacplus_shadow.pl</tt> may be used to keep user passwords out of the <span class="bold"><b class="emphasis">tac_plus</b></span>configuration file, enabling users to change their passwords via the password change dialog. Passwords are stored in an auxiliary, <tt class="literal">/etc/shadow</tt>-like ASCII file, one user per line:</p>
<pre class="screen"><span class="emphasis"><i class="emphasis">username</i></span>:<span class="emphasis"><i class="emphasis">encryptedPassword</i></span>:<span class="emphasis"><i class="emphasis">lastChange</i></span>:<span class="emphasis"><i class="emphasis">minAge</i></span>:<span class="emphasis"><i class="emphasis">maxAge</i></span>:<span class="emphasis"><i class="emphasis">reserved</i></span></pre>
<p><tt class="literal">lastChange</tt> is the number of days since 1970-01-01 when the password was last changed, and <tt class="literal">minAge</tt> and <tt class="literal">maxAge</tt> determine whether the password may/may not/needs to be changed. Setting <tt class="literal">lastChange</tt> to <tt class="literal">0</tt> enforces a password change upon first login.</p>
<p>Example shadow file:</p>
<pre class="screen">marc:$1$q5/vUEsR$jVwHmEw8zAmgkjMShLBg/.:15218:0:99999:
newuser:$1$pQtQsMuj$GKpIr5r2GNaZNfDfnCBtw.:0:0:99999:
test:$1$pQtQsMuj$GKpIr5r2GNaZNfDfnCBtw.:15218:1:30:
</pre>
<p>Sample daemon configuration:</p>
<pre class="screen">
...
  id = tac_plus {
    ...
    mavis module = external {
      setenv SHADOWFILE = /path/to/shadow
      # setenv FLAG_PWPOLICY=y
      # setenv ci=/usr/bin/ci
      exec = /usr/local/lib/mavis/mavis_tacplus_shadow.pl
    }
    ...
    login backend = mavis chpass
    ...
    user = marc {
      login = mavis
      ...
    }
  ...
  }
...</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2632" id="AEN2632">5.5. RADIUS Backends</a></h3>
<p><tt class="literal">mavis_tacplus_radius.pl</tt> authenticates against a RADIUS server. No authorization is done, unless the <tt class="literal">RADIUS_GROUP_ATTR</tt> environment variable is set (see below). This module may, for example, be useful if you have static user account definitions in the configuration file, but authentication passwords should be verified by RADIUS. Use the <tt class="literal">login = mavis</tt> or <tt class="literal">password = mavis</tt> statement in the user profile for this to work.</p>
<p>If the <tt class="literal">Authen::Radius</tt> Perl module is installed, the value of the RADIUS attribute specified by <tt class="literal">RADIUS_GROUP_ATTR</tt> will be used to create a <tt class="literal">TAC_MEMBER</tt> definition which uses the attribute value as group membership. E.g., an attribute value of <tt class="literal">Administrator</tt> would result in a</p>
<pre class="screen">  member = Administrator</pre>
<p>declaration for the authenticated user, enabling authorization and omitting the need for static users in the configuration file.</p>
<p>Keep in mind that authorization will only work well if either</p>
<ul>
<li>
<p>the <tt class="literal">tacplus_info_cache</tt> module is being used (it will cache authentication AV pairs locally, so subsequent authorizations should work fine unless you're switching to a tac_plus server running elsewhere).</p>
</li>
</ul>
<p>or</p>
<ul>
<li>
<p><tt class="literal">single-connection</tt> is used and</p>
</li>
<li>
<p><tt class="literal">mavis cache timeout</tt> is set to a sufficiently high value that covers the user's (expected) maximum login time.</p>
</li>
</ul>
<p>Alternatively to <tt class="literal">mavis_tacplus_radius.pl</tt> the <tt class="literal">pamradius</tt> program may called by the <tt class="literal">external</tt> module. Results should be roughly equivalent.</p>
<div class="section">
<hr>
<h4 class="section"><a name="AEN2663" id="AEN2663">5.5.1. Sample Configuration</a></h4>
<pre class="screen">## Use tacinfo_cache to cache authorization data to disk:
mavis module = tacinfo_cache {
    directory = /tmp/tacinfo
}

## You can use either the Perl module ...
#mavis module = external {
#   exec = /usr/local/lib/mavis_tacplus_radius.pl
#   setenv RADIUS_HOST = 1.2.3.4:1812 # could add more hosts here, comma-separated
#   setenv RADIUS_SECRET = "mysecret"
#   setenv RADIUS_GROUP_ATTR = Class
#   setenv RADIUS_PASSWORD_ATTR = Password # defaults to: User-Password
# }
## ... or the freeradius-client based code:
mavis module = external {
    exec = /usr/local/sbin/radmavis radmavis "group_attribute=Class" "authserver=1.2.3.4:1812:mysecret"
}</pre></div>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2666" id="AEN2666">5.6. Experimental Backends</a></h3>
<p><tt class="literal">mavis_tacplus_sms.pl</tt> is a sample (skeleton) script to send One-Time Passwords via a SMS backend.</p>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2670" id="AEN2670">5.7. Error Handling</a></h3>
<p>If a backend script fails due to an external problem (e.g. LDAP server unavailability), your router may or may not fall back to local authentication (if configured). Chances are, that the fallback doesn't work. If you still want to be able to authenticate via TACACS+ in that case, you can do so with a non-MAVIS user which will only be valid in case of a backend error:</p>
<pre class="screen">    ...
    # set the time interval you want the user to be valid if the backend fails:
    authentication fallback period = 60 # that's actually the default value
    ...
    # add a local user for emergencies:
    user = cisco {
        ...
        fallback-only
        ...
    }</pre>
<p>To indicate that fallback mode is actually active, you may a display a different login prompt to your users:</p>
<pre class="screen">    host = ... {
        ...
        welcome banner = "Welcome\n"
        welcome banner fallback = "Welcome\nEmergency accounts are currently enabled.\n"
        ...
    }</pre>
<p>Fallback can be enabled/disabled globally an on a per-host basis. Default is enabled.</p>
<pre class="screen">    authentication fallback = permit
    host = ... {
        ...
        authentication fallback = deny
        ...
    }</pre></div>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN2678" id="AEN2678">6. Debugging</a></h2>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2681" id="AEN2681">6.1. Debugging Configuration Files</a></h3>
<p>When creating configuration files, it is convenient to check their syntax using the <tt class="literal">-P</tt> flag to <tt class="literal">tac_plus</tt>; e.g:</p>
<pre class="screen">tac_plus -P <span class="emphasis"><i class="emphasis">config-file</i></span> </pre>
<p>will syntax check the configuration file and print any error messages on the terminal.</p>
</div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN2689" id="AEN2689">6.2. Trace Options</a></h3>
<p>Trace (or debugging) options may be specified in <span class="emphasis"><i class="emphasis">global</i></span>, <span class="emphasis"><i class="emphasis">host</i></span>, <span class="emphasis"><i class="emphasis">user</i></span> and <span class="emphasis"><i class="emphasis">group</i></span> context. The current debugging level is a combination (read: <tt class="literal">OR</tt>) of all those. Generic syntax is:</p>
<pre class="screen">debug = <span class="emphasis"><i class="emphasis">option ...</i></span></pre>
<p>For example, getting command authorization to work in a predictable way can be tricky - the exact attributes the NAS sends to the daemon may depend on the IOS version, and may in general not match your expectations. If your regular expressions don't work, add</p>
<pre class="screen">debug = REGEX</pre>
<p>where appropriate, and the daemon may log some useful information to <tt class="literal">syslog</tt>.</p>
<p>Multiple trace options may be specified. Example:</p>
<pre class="screen">debug = REGEX CMD</pre>
<p>Trace options may be removed by prefixing them with<tt class="literal">-</tt>. Example:</p>
<pre class="screen">debug = ALL -PARSE</pre>
<p>The debugging options available are summarized in the following table:</p>
<div class="informaltable"><a name="AEN2709" id="AEN2709"></a>
<table border="1" frame="border" class="CALSTABLE">
<col width="5%" title="col1">
<col width="15%" title="col2">
<col width="30%" title="col3">
<col width="50%" title="col4">
<thead>
<tr>
<th>Bit</th>
<th>Value</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>1</td>
<td>PARSE</td>
<td>Configuration file parsing</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>AUTHOR</td>
<td>Authorization related</td>
</tr>
<tr>
<td>2</td>
<td>4</td>
<td>AUTHEN</td>
<td>Authentication related</td>
</tr>
<tr>
<td>3</td>
<td>8</td>
<td>ACCT</td>
<td>Accounting related</td>
</tr>
<tr>
<td>4</td>
<td>16</td>
<td>CONFIG</td>
<td>Configuration related</td>
</tr>
<tr>
<td>5</td>
<td>32</td>
<td>PACKET</td>
<td>Packet dump</td>
</tr>
<tr>
<td>6</td>
<td>64</td>
<td>HEX</td>
<td>Packet hex-dump</td>
</tr>
<tr>
<td>7</td>
<td>128</td>
<td>LOCK</td>
<td>File locking</td>
</tr>
<tr>
<td>8</td>
<td>256</td>
<td>REGEX</td>
<td>Regular expressions</td>
</tr>
<tr>
<td>9</td>
<td>512</td>
<td>ACL</td>
<td>Access Control Lists</td>
</tr>
<tr>
<td>10</td>
<td>1024</td>
<td>RADIUS</td>
<td>unused</td>
</tr>
<tr>
<td>11</td>
<td>2048</td>
<td>CMD</td>
<td>Command lookups</td>
</tr>
<tr>
<td>12</td>
<td>4096</td>
<td>BUFFER</td>
<td>Buffer handling</td>
</tr>
<tr>
<td>13</td>
<td>8192</td>
<td>PROC</td>
<td>Procedural traces</td>
</tr>
<tr>
<td>14</td>
<td>16384</td>
<td>NET</td>
<td>Network related</td>
</tr>
<tr>
<td>15</td>
<td>32768</td>
<td>PATH</td>
<td>File system path related</td>
</tr>
<tr>
<td>16</td>
<td>65536</td>
<td>CONTROL</td>
<td>Control connection related</td>
</tr>
<tr>
<td>17</td>
<td>131072</td>
<td>INDEX</td>
<td>Directory index related</td>
</tr>
<tr>
<td>18</td>
<td>262144</td>
<td>AV</td>
<td>Attribute-Value pair handling</td>
</tr>
<tr>
<td>19</td>
<td>524288</td>
<td>MAVIS</td>
<td>MAVIS related</td>
</tr>
<tr>
<td>20</td>
<td>1048576</td>
<td>DNS</td>
<td>DNS related</td>
</tr>
<tr>
<td>21</td>
<td>2097152</td>
<td>USERINPUT</td>
<td>Show user input (this may include passwords)</td>
</tr>
<tr>
<td>31</td>
<td>2147483648</td>
<td>NONE</td>
<td>Disable debugging</td>
</tr>
</tbody>
</table>
</div>
<p>Some of those debugging options are not used and trigger no output at all.</p>
<div class="tip">
<table class="tip" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/tip.svg" hspace="5" alt="Tip"></td>
<th align="left" valign="middle"><b>Debugging User Input</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>The daemon will (starting with snapshot 202012051554) by default no longer outputs user input from authentication packets sent by the NAS. You can explicitly change this using the <tt class="literal">USERINPUT</tt> debug flag. Something like</p>
<pre class="screen">debug = ALL</pre>
<p>or using a numeric value will <span class="emphasis"><i class="emphasis">not</i></span> work, it needs to be enabled explicitly, e.g.:</p>
<pre class="screen">debug = ALL USERINPUT</pre>
<p>Be prepared to see plain text user passwords if you enable this option.</p>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN2847" id="AEN2847">7. Frequently Asked Questions</a></h2>
<ul>
<li>
<p><span class="bold"><b class="emphasis">Is there a Graphical User Interface of any kind?</b></span></p>
<p>Old answer: No, unless your favourite text editor does qualify. The configuration syntax is too complex and flexible to be coverable using a GUI. If you're looking for a way to manage your user database then have a look at Webmin, ActiveDirectory, whatever. It's trivial to use those as authentication/authorization backends.</p>
<p>Updated answer: Yes, various, and unrelated. Search for "tacacsgui". There are other adaptors, too.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">How do I use the MySQL backend?</b></span></p>
<p>You don't, unless you're willing to write the SQL backend yourself. This isn't hard, really, but obviously depends a lot on your database structure and there's simply no generic enough way to free you from this step. Just have a look at, e.g., the LDAP Perl scripts that come with the distribution. If you're remotely familiar with Perl and your SQL database, then writing the backend will be a piece of cake.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">I'm using the <span class="emphasis"><i class="emphasis">single-connection</i></span> feature. How can I force my router to close the TCP connections to the TACACS+ server?</b></span></p>
<p>On IOS, <tt class="literal">show tcp brief</tt> will display the TCP connections. Search for the ones terminating at your server, and kill them using <tt class="literal">clear tcp tcb ...</tt>. Example:</p>
<pre class="screen">Router#sho tcp brief | incl 10.0.0.1.49  
633BB794  10.0.0.2.17326              10.0.0.1.49                 ESTAB
6287E4C4  10.0.0.2.24880              10.0.0.1.49                 ESTAB
Router#clear tcp tcb 633BB794            
[confirm]
 [OK]
Router#clear tcp tcb 6287E4C4
[confirm]
 [OK]
Router#</pre></li>
<li>
<p><span class="bold"><b class="emphasis">Does the daemon require a working DNS?</b></span></p>
<p>No, DNS is not a requirement. You may however use DNS reverse mapping in NAC ACL lists, provided that the software is compiled with <tt class="literal">c-ares</tt> support.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">Why do I get PPP authorization failures because of <tt class="literal">no username in request</tt> when I've already logged in and authenticated?</b></span></p>
<p>With <tt class="literal">aaa authentication ppp default group tacacs+</tt>, the ppp authentication overrides the earlier login authentication. If the ppp authentication fails, the username ends up blank. Changing the config to <tt class="literal">aaa authentication ppp default if-needed group tacacs+</tt> fixes this problem.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">Is there any way to avoid having clear text versions of the ARAP and CHAP secrets in the configuration file?</b></span></p>
<p>CHAP and ARAP require that the server knows the cleartext password (or equivalently, something from which the server can generate the cleartext password). Note that this is part of the definition of CHAP and ARAP, not just the whim of some Cisco engineer who drank too much coffee late one night.</p>
<p>If we encrypted the CHAP and ARAP passwords in the database, then we'd need to keep a key around so that the server can decrypt them when CHAP or ARAP needs them. So this only ends up being a slight obfuscation and not much more secure than the original scheme.</p>
<p>In extended TACACS, the CHAP and ARAP secrets were separated from the password file because the password file may be a system password file and hence world readable. But with TACACS+'s native database, there is no such requirement, so we think the best solution is to read-protect the files. Note that this is the same problem that a Kerberos server has. If your security is compromised on the Kerberos server, then your database is wide open. Kerberos does encrypt the database, but if you want your server to automatically restart, then you end up having to "kstash" the key in a file anyway and you're back to the same security problem.</p>
<p>So storing the cleartext password on the security server is really an absolute requirement of the CHAP and ARAP protocols, not something imposed by TACACS+.</p>
<p>With the scheme choosen for newer TACACS+ protocol revisions, the NAS sends the challenge information to the TACACS+ daemon and the daemon uses the cleartext password to generate the response and returns that.</p>
<p>The original TACACS+ protocol included specific protocol knowledge for both ARAP and CHAP. Please note that this version of the daemon implementation no longer supports SENDPASS, SENDAUTH and ARAP to comply to RFC8907.</p>
<p>However, the above doesn't apply to PAP. You can keep an inbound PAP password DES- or MD5-encrypted, since all you need to do with it is verify that the password the principal gave you is correct.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">How is the typical login authentication sequence done?</b></span></p>
<ol type="1">
<li>
<p>NAS sends START packet to daemon</p>
</li>
<li>
<p>Daemon send GETUSER containing login prompt to NAS</p>
</li>
<li>
<p>NAS prompts user for username</p>
</li>
<li>
<p>NAS sends packet to daemon</p>
</li>
<li>
<p>Daemon sends GETPASS containing password prompt to the NAS</p>
</li>
<li>
<p>NAS prompts user for password</p>
</li>
<li>
<p>NAS sends packet to daemon</p>
</li>
<li>
<p>Daemon sends accept, reject or error to NAS</p>
</li>
</ol>
</li>
<li>
<p><span class="bold"><b class="emphasis">What does "<tt class="literal">default service = permit</tt>" really do?</b></span></p>
<p>When a request comes in to authorize exec startup, or ppp (with protocol lcp, ip, ipx), or slip, or arap or a specific command, the daemon looks for a matching declarations for the user (or groups the user is a member of).</p>
<p>For exec startup, it looks for a <tt class="literal">service=shell</tt>.</p>
<p>For PPP, it looks for a <tt class="literal">service=ppp</tt> and <tt class="literal">protocol=</tt> one of <tt class="literal">lcp</tt>, <tt class="literal">ip</tt>, <tt class="literal">ipx</tt>.</p>
<p>For SLIP there must be a <tt class="literal">service=slip</tt> and for ARAP a <tt class="literal">service=arap</tt> clause.</p>
<p>For commands, there must be a matching <tt class="literal">cmd=</tt><span class="emphasis"><i class="emphasis">cmdname</i></span> or a <tt class="literal">default cmd = permit</tt> definition.</p>
<p>If these aren't found, authorization will fail, <span class="emphasis"><i class="emphasis">unless</i></span> you say <tt class="literal">default service = permit</tt>.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">How do I make PAP work?</b></span></p>
<p>Avoid using PAP if possible since it's not very secure. If you <span class="emphasis"><i class="emphasis">must</i></span> use it, PAP passwords may be specified along with ARAP and CHAP passwords for each user.</p>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Passwords</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>It is very bad practice to use an outbound PAP password that is the same as any of your inbound passwords. For this reason, a "global" password, defined with the <tt class="literal">password = clear ...</tt> statement, does not apply to outbound PAP, only to inbound PAP, bidirectional CHAP and ARAP.</p>
</td>
</tr>
</table>
</div>
</li>
<li>
<p><span class="bold"><b class="emphasis">How can I deny telneting from a commserver by IP address only i.e. when command is <tt class="literal">10.0.1.6</tt> rather than <tt class="literal">telnet 10.0.1.6</tt>?</b></span></p>
<p>The best way to restrict telnet access is by applying an outbound access list via the access class command (or equivalently, via the "acl" avpair). The NAS configuration command</p>
<pre class="screen">access-class <span class="emphasis"><i class="emphasis">n</i></span> out</pre>
<p>for example applies a pre-defined standard IP access list (where n is a number from 1 through 99) that governs telnet access from a NAS.</p>
<p>E.g. the following configuration commands permit outgoing Telnet access from line 1 on the NAS *only* to hosts on network 192.85.55.0:</p>
<pre class="screen">access-list 12 permit 192.85.55.0 0.0.0.255
line 1
  access-class 12 out</pre>
<p><span class="emphasis"><i class="emphasis">Note:</i></span> You must define the access-list on the NAS. Only then can you use the acl avpair to apply it to a line that a user dials in on.</p>
<p>Alternatively, you can try configuring <tt class="literal">transport preferred none</tt> on the lines in question. This will force a user to always type <tt class="literal">telnet 10.0.1.6</tt> in order to telnet out from the NAS. Then you can apply command authorization to this command to restrict it.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">I have an autocommand configured in the NAS-local database and I'm using</b></span></p>
<pre class="screen">aaa authentication local-override</pre>
<span class="bold"><b class="emphasis">The autocommand doesn't work, but the username/password does. Why?</b></span>
<p>The <tt class="literal">local-override</tt> only applies to the authentication portion of the local database, so if you want an autocommand for this user, you need to also do:</p>
<pre class="screen">aaa authorization exec local if-authenticated</pre>
<p>This will use the local DB entry if one exists, allow authenticated users otherwise, or fail.</p>
<p>We don't have a <tt class="literal">aaa authorization local-override</tt> like we do for authentication. Unlike authentication, the local method for authorization is sort of equivalent to a local-override.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">Can TACACS+ only be enabled on a global basis?</b></span></p>
<p>You turn TACACS+ <span class="emphasis"><i class="emphasis">ON</i></span> on a global basis, but you can then change the behavior of individual lines to whatever you want, e.g.</p>
<pre class="screen">aaa authentication login default tacacs+ none
aaa authentication login oldstyle line
aaa authentication login none none
line 1 16
  login authentication default
line vty 0 4
  login authentication oldstyle
line 0
  login authentication none</pre>
<p>Note that unfortunately, you can't (yet) apply authorization differently to selected lines and interfaces.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">I have leased lines running PPP, and AAA authorization is also configured, so the authorization on the leased lines fails. What should I do?</b></span></p>
<p>Since you can't (yet) configure authorization on a per-line basis, you have to turn on authentication on the leased lines running PPP and configure your TACACS+ server so that it will authorize these lines correctly.</p>
<p>A more demanding alternative is to modify the TACACS+ server source code to allow any authorizations coming in from the port "SerialXXX" to succeed.</p>
<p>A third possibility is to not use PPP on those lines, e.g. use HDLC instead. HDLC doesn't require authentication or authorization.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">How many characters may a TACACS+ Username and Password contain?</b></span></p>
<p>The short answer is 31 bytes of username, with up to 254 bytes of password if they are cleartext (8 bytes if passwords are DES encrypted).</p>
<p>The long answer is that the Cisco NAS allocates a buffer of 1024 bytes, so this is the maximum you can type in, in response to a NAS prompt.</p>
<p>But the protocol spec allows a username or password length field of just one byte in an authentication packet, so only the first 255 of these characters can be sent to the daemon.</p>
<p>Now if it's a DES encrypted password, then only the first 8 bytes are significant, per the common unix implementations of crypt.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">How do I limit the number of sessions a user can have?</b></span></p>
<p>With this version of the daemon you can't.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">How can I configure time-outs on an interface via TACACS+?</b></span></p>
<p>Certain per-user/per-interface timeouts may be set by TACACS+ during authorization. As of 11.0, you can set an arap session timeout, and an exec timeout. As of 11.1 you can also set an exec idle timeout.</p>
<p>There are currently no settable timeouts for PPP or SLIP sessions, but there is a workaround which applies to ASYNC PPP/SLIP idle timeouts started via exec sessions only: This workaround is to set an EXEC (idletime) timeout on an exec session which is later used to start up PPP or SLIP (either via a TACACS+ autocommand or via the user explicitly invoking PPP or SLIP). In this case, the exec idle timeout will correctly terminate an idle PPP or SLIP session. Note that this workaround cannot be used for sessions which autoselect PPP or SLIP.</p>
<p>An idle timeout terminates a connection when the interface is idle for a given period of time (this is equivalent to the "session-timeout" Cisco IOS configuration directive). The other timeouts are absolute. Of course, any timeouts set by TACACS+ apply only to the current connection.</p>
<pre class="screen">user = lol {
    login = clear foobar
    service = shell {
        set idletime = 5 # disconnect lol if there is no traffic for 5 minutes
        set timeout = 60 # disconnect lol unconditionally after one hour
    }
}</pre>
<p>You also need to configure exec authorization on the NAS for the above timeouts, e.g.</p>
<pre class="screen">aaa authorization exec default group tacacs+</pre>
<p>Note that these timeouts only work for async lines, not for ISDN currently.</p>
<p>Note also that you cannot use the authorization <tt class="literal">if-authenticated</tt> option with these parameters, since that skips authorization if the user has successfully authenticated.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">How do I send VPDN forwarding decisions to an authorization server?</b></span></p>
<p>In 11.2 onwards, VPDN NASs can use TACACS+ to allow an authorization server to make the decision to forward users.</p>
<p>If VPDN forwarding is turned on, and the username is of the form <tt class="literal">user@domain</tt>, and <tt class="literal">domain</tt> matches a vpdn outgoing configured domain, then an authorization attempt is made for <tt class="literal">domain</tt> (see below).</p>
<p>When making an authorization call for VPDN, a service type of <tt class="literal">ppp</tt> with a protocol type of <tt class="literal">vpdn</tt>, with a username of <tt class="literal">domain</tt> will be made e.g. when a PPP user comes up on a line with the username <tt class="literal">foo@bar.com</tt>, if <tt class="literal">vpdn enable</tt> and <tt class="literal">aaa authorization ....</tt> is enabled on the box, then a one-time authorization of the name <tt class="literal">bar.com</tt> is attempted.</p>
<p>If this authorization is successful, no local authentication is attempted on the NAS, and the connection is forwarded via VPDN instead.</p>
<p>If no VPDN-specific information comes back from this authorization call, the login proceeds as follows:</p>
<p>If <tt class="literal">tacacs-server directed-requests</tt> are configured (note: this is true by default), then IOS will strip off the domain part of a name of the form <tt class="literal">user@domain</tt> and use "<tt class="literal">domain</tt>" to try and select a TACACS+ server. If successful, the username portion "<tt class="literal">user</tt>", without the domain, will be used for all subsequent authentication, authorization and accounting.</p>
<p>If directed requests are turned off, then the entire username <tt class="literal">user@domain</tt> is treated as a username.</p>
<p>vpdn specific information includes the attributes <tt class="literal">tunnel-id</tt>, <tt class="literal">source-ip</tt> (deprecated) and <tt class="literal">ip-addresses</tt>:</p>
<div class="informaltable"><a name="AEN3034" id="AEN3034"></a>
<table border="1" class="CALSTABLE">
<col>
<col>
<tbody>
<tr>
<td>tunnel-id</td>
<td>This AV pair specifies the username that will be used to authenticate the tunnel over which the individual user MID will be projected. This is analogous to the "NAS name" in the "vpdn outgoing" command.</td>
</tr>
<tr>
<td>ip-addresses</td>
<td>This is a list of possible IP addresses that can be used for the end-point of the tunnel. Consult the text at the end of this document for more details on how to configure this attribute.</td>
</tr>
<tr>
<td>source-ip</td>
<td><span class="emphasis"><i class="emphasis">This is now deprecated. It began in release 11.2(1.4), and was removed in 11.2(4.0.2).</i></span> This ip address will be used as the source of all VPDN packets generated as part of the VPDN tunnel (see the source-ip keyword in the vpdn outgoing command).</td>
</tr>
</tbody>
</table>
</div>
<p><span class="bold"><b class="emphasis">TACACS+ syntax</b></span></p>
<p>The following syntax is used:</p>
<pre class="screen">  user = domain {
    service = ppp {
      protocol = vpdn {
        set tunnel-id = <span class="emphasis"><i class="emphasis">name for tunnel authentication</i></span>
        set ip-addresses = <span class="emphasis"><i class="emphasis">addr</i></span> <span class="emphasis"><i class="emphasis">[addr ...]</i></span>
        set source-ip = <span class="emphasis"><i class="emphasis">ip-address</i></span>
      }
    }
  }</pre>
<p>In addition the TACACS+ server can be used to store the usernames for both the NAS (the username specified by "tunnel-id" above) and the Home Gateway. These will be used to authenticate the tunnel.</p>
<p>Example:</p>
<pre class="screen">  user = foobar.example.com {
    service = ppp {
      protocol = vpdn {
        set tunnel-id = my_nas
        set ip-addresses = "203.0.113.19 203.0.113.20"
        set source-ip = 197.51.100.1
      }
    }
  }

  user = my_nas { chap = clear egad }

  user = my_home_gateway { chap = clear wowser }</pre>
<p><span class="bold"><b class="emphasis">IOS Configuration</b></span></p>
<p>To enable AAA assisted VPDN forwarding on a NAS, the following minimum configuration is required:</p>
<pre class="screen">vpdn enable
aaa new-model
aaa authorization network default group tacacs+ ...</pre>
<p>In addition, if the passwords for the home gateway and NAS are stored on the TACACS+ daemon, the command</p>
<pre class="screen">aaa authentication login default group tacacs+ ....</pre>
<p>should also be present.</p>
<p>Beginning with release 11.2(1.4), the additional configuration</p>
<pre class="screen">vpdn outgoing example.com ip NAS [ source-ip X.X.X.X ]</pre>
<p>can be used. This changes in 11.2(4.0.2) and becomes:</p>
<pre class="screen">vpdn source-ip X.X.X.X
vpdn outgoing example.com ip NAS</pre></li>
<li>
<p><span class="bold"><b class="emphasis">Can someone expand on the use of the <tt class="literal">optional</tt> keyword?</b></span></p>
<p>Most attributes are mandatory i.e. if the daemon sends them to the NAS, the NAS must obey them or deny the authorization. This is the default. It is possible to mark attributes as optional, in which case a NAS which cannot support the attribute is free to simply ignore it without causing the authorization to fail.</p>
<p>This was intended to be useful in cutover situations where you have multiple NASes running different versions of IOS, some of which support more attributes than others. If you make the new attributes optional, older NASes could ignore the optional attributes while new NASes could apply them. Note that this weakens your security a little, since you are no longer guaranteed that attributes are always applied on successful authorization, so it should be used judiciously.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">Can I do do address pooling on the TACACS+ daemon?</b></span></p>
<p>Not really since nothing on the daemon tracks whether an address is already in use. The best way to manage address pools is to define a non-overlapping pool of addresses on each NAS and return the name of this pool during authorization whenever a user logs in e.g.</p>
<p><span class="bold"><b class="emphasis">NAS:</b></span></p>
<pre class="screen">ip local pool foo 1.0.0.1 1.0.0.10</pre>
<p><span class="bold"><b class="emphasis">Daemon:</b></span></p>
<pre class="screen">user = lol { service = ppp { protocol = ip { set addr-pool = foo } } }</pre></li>
<li>
<p><span class="bold"><b class="emphasis">What about MSCHAP?</b></span></p>
<p>The daemon contains mschap support. Mschap is configured the same way as chap, only using the <tt class="literal">mschap</tt> keyword in place of the <tt class="literal">chap</tt> keyword.</p>
<p>Like ARAP, MSCHAP requires DES support. Use the <tt class="literal">--with-ssl</tt> flag when configuring the package.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN3093" id="AEN3093">8. Canned Configurations</a></h2>
<p>Here are some canned configurations for getting demos started:</p>
<div class="section">
<hr>
<h3 class="section"><a name="AEN3096" id="AEN3096">8.1. Login Authentication</a></h3>
<p>A canned configuration for login authentication only. This allows user <tt class="literal">fred</tt> to login with password <tt class="literal">abcdef</tt>. If the TACACS+ server dies, the enable secret will be accepted as a login password instead.</p>
<p><span class="bold"><b class="emphasis">Daemon:</b></span></p>
<pre class="screen">id = spawnd {
    listen = { port = 49 }
}
id = tac_plus {
    host = any { key = "some key" address = 0.0.0.0/0 }

    # repeat as necessary for each user
    user = fred { login = clear abcdef }
}</pre>
<p><span class="bold"><b class="emphasis">NAS:</b></span></p>
<pre class="screen">aaa new-model
enable secret foobar
! use TACACS+. If server dies, use the enable secret password
aaa authentication login default group tacacs+ enable
tacacs-server host ...
tacacs-server key some key</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN3107" id="AEN3107">8.2. Command Authorization</a></h3>
<p>This will allow user <tt class="literal">fred</tt> to login with password <tt class="literal">abcdef</tt> and to run the privileged (level 15) commands <tt class="literal">write terminal</tt> and <tt class="literal">configure</tt>. All other privileged commands will be denied.</p>
<p>The "none" keyword in the NAS configuration line means that if the TACACS+ server dies, any command will be allowed.</p>
<p><span class="bold"><b class="emphasis">Daemon:</b></span></p>
<pre class="screen">id = spawnd {
    listen = { port = 49 }
}
id = tac_plus {
    host = any { key = "some key" address = 0.0.0.0/0 }

    # repeat as necessary for each user
    user = fred {
        login = clear abcdef
        service = shell {
            cmd = write  { permit terminal }
            cmd = configure { permit .* }
        }
    }
}</pre>
<p><span class="bold"><b class="emphasis">NAS:</b></span></p>
<pre class="screen">aaa new-model
! all level 15 (privileged commands). If server dies, allow everything
aaa authorization commands 15 default group tacacs+ none
tacacs-server host 10.1.1.1
tacacs-server key some key</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN3121" id="AEN3121">8.3. Network Access Authorization</a></h3>
<p>This config allows <tt class="literal">fred</tt> to login to <tt class="literal">line 1</tt> with password <tt class="literal">abcdef</tt> (or to and to run ppp using chap authentication. The chap password is <tt class="literal">lab</tt>.</p>
<p><span class="bold"><b class="emphasis">Daemon:</b></span></p>
<pre class="screen">id = spawnd {
    listen = { port = 49 }
}
id = tac_plus {
    host = any { key = "some key" address = 0.0.0.0/0 }

    # repeat as necessary for each user
    user = fred {
        login = clear abcdef
        chap = clear lab
        service = ppp { protocol = ip { set addr=1.0.0.2 } }
    }
}</pre>
<p><span class="bold"><b class="emphasis">NAS:</b></span></p>
<pre class="screen">aaa new-model
! authenticate exec logins (if not autoselecting)
aaa authentication login default group tacacs+
! authorize network services via TACACS+
aaa authorization network default group tacacs+
! use TACACS+ for authenticating ppp users
aaa authentication ppp default group tacacs+ 
tacacs-server host 10.1.1.1
tacacs-server key some key
interface Async1
ip address 1.0.0.1 255.0.0.0
async default ip address 172.21.14.55
encapsulation ppp
async dynamic address
async mode interactive
! use chap to authenticate ppp users
ppp authentication chap
line 1
! need "modem inout" here and flow control if using a modem</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN3134" id="AEN3134">8.4. ARAP</a></h3>
<p><span class="bold"><b class="emphasis">Daemon:</b></span></p>
<pre class="screen">id = spawnd {
    listen = { port = 49 }
}
id = tac_plus {
    host = any { key = "some key" address = 0.0.0.0/0 }

    user = lol {
        arap = clear arapSecret
        service = arap
    }
}</pre>
<p><span class="bold"><b class="emphasis">NAS:</b></span></p>
<pre class="screen">aaa new-model
aaa authentication arap default group tacacs+
aaa authorization network default group tacacs+
aaa accounting network default start-stop group tacacs+
!
appletalk routing
arap network ...
!
interface Ethernet0
  appletalk cable-range ...
  appletalk zone ...
!
tacacs-server host ...
tacacs-server key ...
!
line 1
  location a modem
  modem answer-timeout 0
  modem InOut
  autoselect arap
  autoselect during-login
  arap enable
  speed ...
  flowcontrol hardware</pre></div>
<div class="section">
<hr>
<h3 class="section"><a name="AEN3142" id="AEN3142">8.5. Callback</a></h3>
<div class="note">
<table class="note" width="100%" border="0">
<tr>
<td width="25" align="center" valign="top"><img src="images/note.svg" hspace="5" alt="Note"></td>
<th align="left" valign="middle"><b>Availability of Callback</b></th>
</tr>
<tr>
<td>&nbsp;</td>
<td align="left" valign="top">
<p>Callback is available only in IOS 11.1 and later, and can only be controlled via TACACS+ for ASYNC lines. ISDN callback can be configured on the NAS but cannot be controlled via AAA.</p>
</td>
</tr>
</table>
</div>
<p>Here is an example of AAA configuration (with exec and network accounting enabled):</p>
<p><span class="bold"><b class="emphasis">Daemon:</b></span></p>
<p>Example of remote TACACS+ server configuration file entry for username <tt class="literal">foobar</tt>:</p>
<pre class="screen">id = spawnd {
    listen = { port = 49 }
}
id = tac_plus {
    host = any { key = "some key" address = 0.0.0.0/0 }

    user = foobar {
        arap = clear AAAA
        login = clear LLLL
        chap = clear CCCC
        pap = clear PPPP
        service = ppp {
            default protocol = permit
            protocol = lcp {
                set callback-dialstring=123456
            }
        }
        service = arap {
            protocol = atalk {
                set callback-dialstring=2345678
            }
        }
        service = shell {
            set callback-dialstring=3456789
            set callback-line=7
            set nocallback-verify=1
        }
    }
}</pre>
<p><span class="bold"><b class="emphasis">NAS:</b></span></p>
<pre class="screen">aaa new-model
tacacs-server host XX.XX.XX.XX
tacacs-server key fookey
aaa accounting exec wait-start tacacs+
aaa accounting network wait-start tacacs+

! Example of AAA configuration for Exec:
aaa authentication login execcheck tacacs+
aaa authorization network tacacs+
service exec-callback

line 4
  login authentication execcheck

! Example of AAA configuration for ARAP:
aaa authentication arap arapcheck tacacs+
aaa authorization network tacacs+
arap callback

line 4
  arap authentication arapcheck

! Example of AAA-specific configuration for PPP callback:
aaa new-model
aaa authentication ppp pppcheck tacacs+
aaa authorization network tacacs+

int async 6
  ppp authentication chap pppcheck
  ppp callback accept</pre></div>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN3156" id="AEN3156">9. Authorization AV pairs</a></h2>
<p>The following authorization AV pairs specify which service is being authorized and are typically accompanied by protocol AV pairs and other, additional pairs from the lists below. (For a complete and current list of supported AV pairs and required IOS releases search <a class="lk" href="http://www.cisco.com/" target="_top">http://www.cisco.com/</a> for "TACACS+ Attribute-Value Pairs".)</p>
<ul>
<li>
<p><tt class="literal">service=arap</tt></p>
</li>
<li>
<p><tt class="literal">service=shell</tt></p>
<p>Used for exec startup, and also for command authorizations.</p>
</li>
<li>
<p><tt class="literal">service=ppp</tt></p>
</li>
<li>
<p><tt class="literal">service=slip</tt></p>
</li>
<li>
<p><tt class="literal">service=system</tt></p>
<p>Not used</p>
</li>
<li>
<p><tt class="literal">service=raccess</tt></p>
<p>Used for managing reverse telnet connections, e.g.:</p>
<pre class="screen">user = jim {
login = clear lab
    service = raccess {
        set port#1 = nasname1/tty2
        set port#2 = nasname2/tty5
    }
}</pre>
<p>Requires IOS configuration:</p>
<pre class="screen">aaa authorization reverse-access default group tacacs+ </pre>
<p>See the IOS docs for more details.</p>
</li>
<li>
<p><tt class="literal">protocol=lcp</tt></p>
<p>The lower layer of PPP, always brought up before IP, IPX, etc. is brought up.</p>
</li>
<li>
<p><tt class="literal">protocol=ip</tt></p>
<p>Used with <tt class="literal">service=ppp</tt> and <tt class="literal">service=slip</tt> to indicate which protocol layer is being authorized.</p>
</li>
<li>
<p><tt class="literal">protocol=ipx</tt></p>
<p>Used with <tt class="literal">service=ppp</tt> to indicate which protocol layer is being authorized.</p>
</li>
<li>
<p><tt class="literal">protocol=atalk</tt></p>
<p>Used with <tt class="literal">service=ppp</tt> or <tt class="literal">service=arap</tt>.</p>
</li>
<li>
<p><tt class="literal">protocol=vines</tt></p>
<p>For VINES over PPP.</p>
</li>
<li>
<p><tt class="literal">protocol=ccp</tt></p>
<p>Authorization of CCP (Compression Control Protocol). No other av-pairs associated with this.</p>
</li>
<li>
<p><tt class="literal">protocol=cdp</tt></p>
<p>Authorization of CDP (Cisco Discovery Protocol). No other av-pairs associated with this.</p>
</li>
<li>
<p><tt class="literal">protocol=multilink</tt></p>
<p>Authorization of multilink PPP. See <tt class="literal">max-links</tt> and <tt class="literal">load-threshold</tt>.</p>
</li>
<li>
<p><tt class="literal">protocol=unknown</tt></p>
<p>For undefined/unsupported conditions. Should not occur under normal circumstances.</p>
</li>
<li>
<p><tt class="literal">cmd</tt> (EXEC)</p>
<p>If the value of cmd is NULL e.g. the AV pair is <tt class="literal">cmd=</tt>, then this is an authorization request for starting an exec (shell). If <tt class="literal">cmd</tt> is non-null, this is a command authorization request, It contains the name of the command being authorized, e.g. <tt class="literal">cmd=telnet</tt>.</p>
</li>
<li>
<p><tt class="literal">cmd-arg</tt> (EXEC)</p>
<p>During command authorization, the name of the command is given by an accompanying <tt class="literal">cmd=</tt> AV pair, and each command argument is represented by a cmd-arg AV pair e.g. <tt class="literal">cmd-arg=archie.sura.net</tt> <span class="emphasis"><i class="emphasis">Note:</i></span> <tt class="literal">cmd-arg</tt> should never appear in a configuration file. It is used internally by the daemon to construct a string which is then matched against the regular expressions which appear in a <tt class="literal">cmd</tt> clause in the configuration file.</p>
</li>
<li>
<p><tt class="literal">acl</tt> (ARAP, EXEC)</p>
<p>For ARAP this contains an access-list number. For EXEC authorization it contains an access-class number, e.g. <tt class="literal">acl=2</tt>. which is applied to the line as the output access class equivalent to the configuration command</p>
<pre class="screen">line ...
  access-class 2 out</pre>
<p>An outbound access-class is the best way to restrict outgoing telnet connections. Note that a suitable access list (in this case, numbered 2) must be predefined on the NAS.</p>
</li>
<li>
<p><tt class="literal">inacl</tt> (PPP/IP/IPX)</p>
<p>This AV pair contains an IP or IPX input access list number for slip or PPP e.g. <tt class="literal">inacl=2</tt>. The access list itself must be pre-configured on the Cisco box. Per-user access lists do not work with ISDN interfaces unless you also configure a virtual interface. After 11.2(5.1)F, you can also use the name of a predefined named access list, instead of a number, for the value of this attribute. <span class="emphasis"><i class="emphasis">Note:</i></span> For IPX, <tt class="literal">inacl</tt> is only valid after 11.2(4)F.</p>
</li>
</ul>
<ul>
<li>
<p><tt class="literal">inacl#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IP, PPP/IPX, 11.2(4)F)</p>
<p>This AV pair contains the definition of an input access list to be installed and applied to an interface for the duration of the current connection, e.g.</p>
<pre class="screen">inacl#1="permit ip any any precedence immediate"
inacl#2="deny igrp 0.0.1.2 255.255.0.0 any"</pre>
Attributes are sorted numerically before they are applied. For IP, standard OR extended access list syntax may be used, but it is an error to mix the two within a given access-list. For IPX, only extended access list syntax may be used. See also:
<pre class="screen">sho ip access-lists
sho ip interface
sho ipx access-lists 
sho ipx interface
debug aaa author
debug aaa per-user</pre></li>
<li>
<p><tt class="literal">outacl</tt> (PPP/IP, PPP/IPX)</p>
<p>This AV pair contains an IP or IPX output access list number for SLIP. PPP/IP or PPP/IPX connections e.g. outacl=4. The access list itself must be pre-configured on the Cisco box. Per-user access lists do not work with ISDN interfaces unless you also configure a virtual interface. PPP/IPX is supported in 11.1 onwards only. After 11.2(5.1)F, you can also use the name of a predefined named access list, as well as a number, for the value of this attribute.</p>
</li>
<li>
<p><tt class="literal">outacl#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IP, PPP/IPX, 11.2(4)F)</p>
<p>This AV pair contains an output access list definition to be installed and applied to an interface for the duration of the current connection, e.g.</p>
<pre class="screen">outacl#1="permit ip any any precedence immediate"
outacl#2="deny igrp 0.0.9.10 255.255.0.0 any"</pre>
<p>Attributes are sorted numerically before they are applied. For IP, standard OR extended access list syntax may be used, but it is an error to mix the two within a given access-list. For IPX, only extended access list syntax may be used.</p>
<p>See also:</p>
<pre class="screen">sho ip access-lists
sho ip interface
sho ipx access-lists 
sho ipx interface
debug aaa author
debug aaa per-user</pre></li>
<li>
<p><tt class="literal">addr</tt> (SLIP, PPP/IP)</p>
<p>The IP address the remote host should be assigned when a slip or PPP/IP connection is made e.g. <tt class="literal">addr=1.2.3.4</tt>.</p>
</li>
<li>
<p><tt class="literal">routing</tt> (SLIP, PPP/IP)</p>
<p>Equivalent to the <tt class="literal">/routing</tt> flag in <tt class="literal">slip</tt> and <tt class="literal">ppp</tt> commands. Can have as its value the string <tt class="literal">true</tt> or <tt class="literal">false</tt>.</p>
</li>
<li>
<p><tt class="literal">timeout</tt> (11.0 onwards, ARAP, EXEC)</p>
<p>Sets the time until an arap or exec session disconnects unconditionally (in minutes), e.g. <tt class="literal">timeout=60</tt>.</p>
</li>
<li>
<p><tt class="literal">autocmd</tt> (EXEC)</p>
<p>During exec startup, this specifies an autocommand, like the autocommand option to the username configuration command, e.g. <tt class="literal">autocmd="telnet foo.com"</tt>.</p>
</li>
<li>
<p><tt class="literal">noescape</tt> (EXEC)</p>
<p>During exec startup, this specifies "noescape", like the noescape option to the username configuration command. Can have as its value the string <tt class="literal">true</tt> or <tt class="literal">false</tt>, e.g. <tt class="literal">noescape=true</tt>.</p>
</li>
<li>
<p><tt class="literal">nohangup</tt> (EXEC)</p>
<p>During exec startup, this specifies <tt class="literal">nohangup</tt>, like the nohangup option to the username configuration command. Can have as its value the string <tt class="literal">true</tt> or <tt class="literal">false</tt>, e.g. <tt class="literal">nohangup=true</tt>.</p>
</li>
<li>
<p><tt class="literal">priv-lvl</tt> (EXEC)</p>
<p>Specifies the current privilege level for command authorizations, a number from zero to 15 e.g. <tt class="literal">priv-lvl=5</tt>. Note: in 10.3 this attribute was <tt class="literal">priv_lvl</tt> i.e. it contained an underscore instead of a hyphen.</p>
</li>
<li>
<p><tt class="literal">zonelist</tt> (ARAP)</p>
<p>An Appletalk zonelist for arap equivalent to the line configuration command <tt class="literal">arap zonelist</tt>, e.g. <tt class="literal">zonelist=5</tt>.</p>
</li>
<li>
<p><tt class="literal">addr-pool</tt> (11.0 onwards, PPP/IP, SLIP)</p>
<p>This AV pair specifies the name of a local pool from which to get the IP address of the remote host. Note: <tt class="literal">addr-pool</tt> works in conjunction with local pooling. It specifies the name of a local pool (which needs to be pre-configured on the NAS). Use the ip-local pool command to declare local pools, e.g on the NAS:</p>
<pre class="screen">ip address-pool local ip local pool foo 1.0.0.1 1.0.0.10
ip local pool baz 2.0.0.1 2.0.0.20</pre>
<p>Then you can use TACACS+ to return <tt class="literal">addr-pool=foo</tt> or <tt class="literal">addr-pool=baz</tt> to indicate which address pool you want to get this remote node's address from, e.g. on the daemon:</p>
<pre class="screen">user = lol { service = ppp { protocol = ip { set addr-pool=foo } }</pre></li>
<li>
<p><tt class="literal">route</tt> (11.1 onwards, PPP/IP, SLIP).</p>
<p>This AV pair specifies a route to be applied to an interface. During network authorization, the "route" attribute may be used to specify a per-user static route, to be installed via TACACS+. The daemon side declaration is:</p>
<pre class="screen">service = ppp {protocol=ip{set route="<span class="emphasis"><i class="emphasis">dst_addr</i></span> <span class="emphasis"><i class="emphasis">mask</i></span> <span class="emphasis"><i class="emphasis">[</i></span> <span class="emphasis"><i class="emphasis">gateway</i></span> <span class="emphasis"><i class="emphasis">]</i></span>"}}</pre>
<p>This indicates a temporary static route that is to be applied. <span class="emphasis"><i class="emphasis">dst_address</i></span>, <span class="emphasis"><i class="emphasis">mask</i></span> and <span class="emphasis"><i class="emphasis">gateway</i></span> are expected to be in the usual dotted-decimal notation, with meanings the same as for the familiar <tt class="literal">ip route</tt> configuration command on a NAS. If gateway is omitted, the peer's address is taken to be the gateway. The route is expunged once the connection terminates.</p>
</li>
<li>
<p><tt class="literal">route#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IP/IPX, 11.2(4)F)</p>
<p>Same as the <tt class="literal">route</tt> attribute, except that these are valid for IPX as well as IP, and they are numbered, allowing multiple routes to be applied e.g.</p>
<pre class="screen">route#1="3.0.0.0 255.0.0.0 1.2.3.4"
route#2="4.0.0.0 255.0.0.0"</pre>
<p>or, for IPX,</p>
<pre class="screen">route#1="4C000000 ff000000 30.12.3.4"
route#2="5C000000 ff000000 30.12.3.5"</pre>
<p>See also:</p>
<pre class="screen">sho ip route
sho ipx route
debug aaa author
debug aaa per-user</pre></li>
<li>
<p><tt class="literal">callback-rotary</tt> (11.1 onwards, valid for ARAP, EXEC, SLIP or PPP)</p>
<p>The number of a rotary group (between 0 and 100 inclusive) to use for callback e.g. <tt class="literal">callback-rotary=34</tt>. Not valid for ISDN.</p>
</li>
<li>
<p><tt class="literal">callback-dialstring</tt> (11.1 onwards, valid for ARAP, EXEC, SLIP or PPP)</p>
<p>sets the telephone number for a callback e.g. <tt class="literal">callback-dialstring=408-555-1212</tt>. Not valid for ISDN.</p>
</li>
<li>
<p><tt class="literal">callback-line</tt> (11.1 onwards, valid for ARAP, EXEC, SLIP or PPP)</p>
<p>The number of a tty line to use for callback e.g. <tt class="literal">callback-line=4</tt>. Not valid for ISDN.</p>
</li>
<li>
<p><tt class="literal">nocallback-verify</tt> (11.1 onwards, valid for ARAP, EXEC)</p>
<p>Indicates that no callback verification is required. The only valid value for this parameter is the digit one i.e. <tt class="literal">nocallback-verify=1</tt>. Not valid for ISDN.</p>
</li>
<li>
<p><tt class="literal">idletime</tt> (11.1 onwards, EXEC)</p>
<p>Sets a value, in minutes, after which an IDLE session will be terminated. <span class="emphasis"><i class="emphasis">Note:</i></span> Does NOT work for PPP.</p>
</li>
<li>
<p><tt class="literal">tunnel-id</tt> (11.2 onwards, PPP/VPDN)</p>
<p>This AV pair specifies the username that will be used to authenticate the tunnel over which the individual user MID will be projected. This is analogous to the "NAS name" in the <tt class="literal">vpdn outgoing</tt> command.</p>
</li>
<li>
<p><tt class="literal">ip-addresses</tt> (11.2 onwards, PPP/VPDN)</p>
<p>This is a space separated list of possible IP addresses that can be used for the end-point of the tunnel. In 11.2(5.4)F, this attribute was extended as follows:</p>
<ol type="1">
<li>
<p>comma ('<tt class="literal">,</tt>') is also considered as a delimiter. For example the avpair can now be written as</p>
<pre class="screen">ip-addresses = 172.21.9.26,172.21.9.15,172.21.9.4</pre></li>
<li>
<p>slash ('<tt class="literal">/</tt>') is considered a priority delimiter. When you have a number of Home Gateway routers, it is desirable to consider some as the primary routers and some as backup routers. '<tt class="literal">/</tt>' allow you to config the routers into priority groups, so that the NAS will try to forward the users to the high priority routers, before forwarding to the low priority one.</p>
<p>For example in the following av-pair:</p>
<pre class="screen">ip-addresses = "172.21.9.26 / 172.21.9.15 / 172.21.9.4"</pre>
<p>172.21.9.26 is considered to be priority 1,</p>
<p>172.21.9.15 is considered to be priority 2,</p>
<p>172.21.9.4 is considered to be priority 3.</p>
<p>The NAS will try to forward the users to 172.21.9.26, before trying 172.21.9.15. If the NAS can't forward users to 172.21.9.26, it will try 172.21.9.15 next. If it fails with 172.21.9.15, it will then try forwarding to 172.21.9.4.</p>
</li>
</ol>
</li>
<li>
<p><tt class="literal">source-ip</tt> (PPP/VPDN, now deprecated, only existed in releases 11.2(1.4) thru 11.2(4.0.2))</p>
<p>This specifies a single ip address will be used as the source of all VPDN packets generated as part of the VPDN tunnel (see the equivalent source-ip keyword in the IOS vpdn outgoing command).</p>
</li>
<li>
<p><tt class="literal">nas-password</tt> (PPP/VPDN, 11.2(3.4)F, 11.2(4.0.2)F)</p>
<p>During L2F tunnel authentication, nas-password specifies the password for the NAS.</p>
</li>
<li>
<p><tt class="literal">gw-password</tt> (PPP/VPDN, 11.2(3.4)F, 11.2(4.0.2)F)</p>
<p>During L2F tunnel authentication, gw-password specifies the password for the home gateway.</p>
</li>
<li>
<p><tt class="literal">rte-ftr-in#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP -- IP/IPX, 11.2(4)F)</p>
<p>This AV pair specifies an input access list definition to be installed and applied to routing updates on the current interface, for the duration of the current connection. For IP, both standard and extended Cisco access list syntax is recognised, but it is an error to mix the two within a given access-list. For IPX, only Cisco extended access list syntax is legal. Attributes are sorted numerically before being applied. For IP, the first attribute must contain the name of a routing process and its identifier (except for rip, where no identifier is needed), e.g.</p>
<pre class="screen">rte-fltr-in#0="router igrp 60"
rte-fltr-in#1="permit 0.0.3.4 255.255.0.0"
rte-fltr-in#2="deny any"</pre>
<p>For IPX, no routing process is needed, e.g.</p>
<pre class="screen">rte-fltr-in#1="deny 3C01.0000.0000.0001"
rte-fltr-in#2="deny 4C01.0000.0000.0002"</pre>
<p>See also:</p>
<pre class="screen">show ip access-lists
show ip protocols
sho ipx access-lists 
sho ipx interface
debug aaa author
debug aaa per-user

router ...
[no] distribute-list ...

ipx input-network-filter ...</pre></li>
<li>
<p><tt class="literal">rte-ftr-out#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IP, 11.2(4)F)</p>
<p>This AV pair specifies an input access list definition to be installed and applied to routing updates on the current interface, for the duration of the current connection. For IP, both standard and extended Cisco access list syntax is recognised, but it is an error to mix the two within a given access-list. Attributes are sorted numerically before being applied. The first attribute must contain the name of a routing process and its identifier (except for rip, where no identifier is needed), e.g.</p>
<pre class="screen">rte-fltr-out#0="router igrp 60"
rte-fltr-out#3="permit 0.0.5.6 255.255.0.0"
rte-fltr-out#4="permit any"</pre>
<p>For IPX, no routing process is specified, e.g.</p>
<pre class="screen">rte-fltr-out#1="deny 3C01.0000.0000.0001"
rte-fltr-out#2="deny 4C01.0000.0000.0002"</pre>
<p>See also:</p>
<pre class="screen">sho ipx access-lists 
sho ipx interface
show ip access-lists
show ip protocols
debug aaa author
debug aaa per-user

router ...
  [no] distribute-list ...

ipx output-network-filter ...</pre></li>
<li>
<p><tt class="literal">sap#</tt><span class="emphasis"><i class="emphasis">n</i></span> (11.2(4)F PPP/IPX)</p>
<p>This AV pair specifies static saps to be installed for the duration of a connection e.g.</p>
<pre class="screen">sap#1="4 CE1-LAB 1234.0000.0000.0001 451 4"
sap#2="5 CE3-LAB 2345.0000.0000.0001 452 5"</pre>
<p>The syntax of static saps is the same as that used by the IOS <tt class="literal">ipx sap</tt> command.</p>
<p>See also:</p>
<pre class="screen">sho ipx servers
debug aaa author
debug aaa per-user
[no] ipx sap ...</pre></li>
<li>
<p><tt class="literal">route#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IP/IPX, 11.2(4)F)</p>
<p>Same as the <tt class="literal">route</tt> attribute, except that these are valid for IPX as well as IP, and they are numbered, allowing multiple routes to be applied e.g.</p>
<pre class="screen">route#1="3.0.0.0 255.0.0.0 1.2.3.4"
route#2="4.0.0.0 255.0.0.0"</pre>
<p>or, for IPX,</p>
<pre class="screen">route#1="4C000000 ff000000 30.12.3.4"
route#2="5C000000 ff000000 30.12.3.5"</pre>
<p>See also:</p>
<pre class="screen">sho ip route
sho ipx route
debug aaa author
debug aaa per-user</pre></li>
<li>
<p><tt class="literal">sap-fltr-in#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IPX, 11.2(4)F)</p>
<p>This AV pair specifies an input sap filter access list definition to be installed and applied on the current interface, for the duration of the current connection. Only Cisco extended access list syntax is legal, e.g</p>
<pre class="screen">sap-fltr-in#1="deny 6C01.0000.0000.0001"
sap-fltr-in#2="permit -1"</pre>
<p>Attributes are sorted numerically before being applied.</p>
<p>See also:</p>
<pre class="screen">sho ipx access-lists 
sho ipx interface
debug aaa author
debug aaa per-user
ipx input-sap-filter ...</pre></li>
<li>
<p><tt class="literal">sap-fltr-out#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IPX 11.2(4)F)</p>
<p>This AV pair specifies an output sap filter access list definition to be installed and applied on the current interface, for the duration of the current connection. Only Cisco extended access list syntax is legal, e.g</p>
<pre class="screen">sap-fltr-out#1="deny 6C01.0000.0000.0001"
sap-fltr-out#2="permit -1"</pre>
<p>Attributes are sorted numerically before being applied.</p>
<p>See also:</p>
<pre class="screen">sho ipx access-lists 
sho ipx interface
debug aaa author
debug aaa per-user
ipx output-sap-filter ...</pre></li>
<li>
<p><tt class="literal">pool-def#</tt><span class="emphasis"><i class="emphasis">n</i></span> (PPP/IP, 11.2(4)F)</p>
<p>This attribute is used to define ip address pools on the NAS. During IPCP address negotiation, if an ip pool name is specified for a user (see the addr-pool attribute), a check is made to see if the named pool is defined on the NAS. If it is, the pool is consulted for an ip address. If the required pool is not present on the NAS (either in the local config, or as a result of a previous download operation), then an authorization call to obtain it is attempted, using the special username:</p>
<pre class="screen"><span class="emphasis"><i class="emphasis">nas-name</i></span>-pools</pre>
where <span class="emphasis"><i class="emphasis">nas-name</i></span> is the configured name of the NAS. <span class="emphasis"><i class="emphasis">Note:</i></span> This username can be changed using the IOS configuration directive e.g.
<pre class="screen">aaa configuration config-name nas1-pools-definition.cisco.us</pre>
<p>The <tt class="literal">pool-def</tt> attribute is used to define ip address pools for the above authorization call e.g.</p>
<pre class="screen">user = foo {
    login = clear lab
    service = ppp { protocol = ip { set addr-pool=bbb } }
}

user = nas1-pools {
    service = ppp {
        protocol = ip {
            set pool-def#1 = "aaa 1.0.0.1 1.0.0.3"
                set pool-def#2 = "bbb 2.0.0.1 2.0.0.10"
                set pool-def#3 = "ccc 3.0.0.1 3.0.0.20"
                set pool-timeout = 60
        }
    }
}</pre>
<p>In the example above is a configuration file fragment for defining 3 pools named <tt class="literal">aaa</tt>, <tt class="literal">bbb</tt> and <tt class="literal">ccc</tt> on the NAS named <tt class="literal">nas1</tt>. When the user <tt class="literal">foo</tt> refers to the pool named <tt class="literal">bbb</tt>, if the pool <tt class="literal">bbb</tt> isn't defined, the NAS will attempt to download the definition contained in the <tt class="literal">nas1-pools</tt> entry. The other pools will also be defined at the same time (or they will be ignored if they are already defined). Since this procedure is only activated when an undefined pool is referenced, one way to redefine a pool once it has been downloaded is to manually delete the definition e.g. by logging into the NAS, enabling, and configuring:</p>
<pre class="screen">config t
no ip local pool bbb
^Z</pre>
<p>When a pool is deleted, there is no interruption in service for any user who is currently using a pool address. If a pool is deleted and then subsequently redefined to include a pool address that was previously allocated, the new pool will pick up the allocated address and track it as expected. Since downloaded pools do not appear in the NAS configuration, any downloaded pool definitions automatically disappear whenever a NAS reboots. These pools are marked as "dynamic" when they appear in the output of the <tt class="literal">show ip local pools</tt> NAS command. Since it is desirable not to have to manually delete pools to redefine them, the AV pair <tt class="literal">pool-timeout=</tt><span class="emphasis"><i class="emphasis">n</i></span> can be used to timeout any downloaded pool definitions. The timeout <span class="emphasis"><i class="emphasis">n</i></span> is in minutes. The effect of the <tt class="literal">pool-timeout</tt> attribute is to start a timer when the pool definitions are downloaded. When the timer expires, the pools are deleted. The next reference to a deleted pool via will cause a re-fetch of the pool definitions. This allows pool changes to be made on the daemon and propagated to the NAS in a timely manner. See also:</p>
<pre class="screen">sho ip local pool ...
ip local pool ...</pre></li>
<li>
<p><tt class="literal">old-prompts</tt> (PPP/SLIP)</p>
<p>This attribute allows providers to make the prompts in TACACS+ appear identical to those of earlier systems (TACACS and XTACACS). This will allow administrators to upgrade from TACACS/XTACACS to TACACS+ transparently to users. The difference between the prompts is as follows: In XTACACS, when the user types <tt class="literal">slip</tt> or <tt class="literal">ppp</tt> the system prompts for an address followed by a password, whereas TACACS+ prompts only for an address. In XTACACS, if the user types <tt class="literal">slip host</tt> or <tt class="literal">ppp host</tt>, the system prompts for a password. In TACACS+, there is no prompt. Using this attribute, TACACS+ can be made to mimic the prompting behaviour of xtacacs, by configuring network authorization on IOS, and using the <tt class="literal">old-prompts=true</tt> attribute value pair for slip and ppp/ip, viz:</p>
<pre class="screen">user = joe {
    service = shell { }
    service = slip {
        default attribute = permit
        set old-prompts=true
    }
    service = ppp {
        protocol = ip {
            default attribute = permit
            set old-prompts=true
        }
    }
}</pre>
<p>i.e. the prompts are controlled by the addition of the <tt class="literal">old-prompts=true</tt> attribute.</p>
</li>
<li>
<p><tt class="literal">max-links</tt> (PPP/multilink - Multilink parameter; 11.3)</p>
<p>This AV pair restricts the number of multilink bundle links that a user can have. The daemon side declaration is:</p>
<pre class="screen">service=ppp { protocol=multilink { set max-links=n } }</pre>
<p>The range of <span class="emphasis"><i class="emphasis">n</i></span> is [1-255].</p>
<p>Related NAS commands:</p>
<pre class="screen">int foo
  [no] ppp multilink

int virtual-template X
  multilink max-links n
show ppp multilink
debug multilink</pre></li>
<li>
<p><tt class="literal">load-threshold</tt> (PPP/multilink - Multilink parameter; 11.3)</p>
<p>This AV pair sets the load threshold at which an additional multilink link is added to the bundle (if load goes above) or deleted (if load goes below). The daemon side declaration is:</p>
<pre class="screen">service=ppp { protocol=multilink { set load-threshold=<span class="emphasis"><i class="emphasis">n</i></span> } }
</pre>
<p>The range of <span class="emphasis"><i class="emphasis">n</i></span> is [1-255]. Related NAS commands:</p>
<pre class="screen">int foo
 [no] ppp multilink

int virtual-template X
  multilink load-threshold n

show ppp multilink

debug multilink
</pre></li>
<li>
<p><tt class="literal">ppp-vj-slot-compression</tt></p>
<p>Reserved for future use.</p>
</li>
<li>
<p><tt class="literal">link-compression</tt></p>
<p>Reserved for future use.</p>
</li>
<li>
<p><tt class="literal">asyncmap</tt></p>
<p>Reserved for future use.</p>
</li>
<li>
<p><tt class="literal">x25-addresses</tt> (PPP/VPDN)</p>
<p>Reserved for future use.</p>
</li>
<li>
<p><tt class="literal">frame-relay</tt> (PPP/VPDN)</p>
<p>Reserved for future use.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN3571" id="AEN3571">10. Upgrading from Previous Releases</a></h2>
<p>There may be some caveats to consider if you're using a previous version of the software:</p>
<ul>
<li>
<p>16-08-2009: To use the MAVIS backend for users not defined in the local configuration file, <tt class="literal">user backend = mavis</tt> is now required.</p>
</li>
<li>
<p>13-06-2010: LDAP functionality was merged into a single script, requiring the environmental variable <tt class="literal">LDAP_SERVER_TYPE</tt> to be set to <tt class="literal">generic</tt> if you were using the <tt class="literal">mavis_tacplus_ldap_authonly.pl</tt> script, to <tt class="literal">tacplus_schema</tt> for functionality equivalent to <tt class="literal">mavis_tacplus_ldap.pl</tt>, and to <tt class="literal">microsoft</tt> for <tt class="literal">mavis_tacplus_ads.pl</tt> functionality.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN3587" id="AEN3587">11. Bugs</a></h2>
<ul>
<li>
<p>There may still be some nasty bugs lurking in the code. Please contact the author via the "Event-Driven Servers" Google Group at <code class="email">&lt;<a class="lk" href="mailto:event-driven-servers@googlegroups.com">event-driven-servers@googlegroups.com</a>&gt;</code> or <a class="lk" href="http://groups.google.com/group/event-driven-servers" target="_top">http://groups.google.com/group/event-driven-servers</a> if you think you've found one.</p>
</li>
<li>
<p>This documentation isn't well structured.</p>
</li>
<li>
<p>The examples given are too IPv4-centric. However, the daemon handles IPv6 just fine.</p>
</li>
<li>
<p>Some of the NAS configuration examples aren't recently tested. Refer to the IOS documentation for IOS configuration syntax guidance.</p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN3601" id="AEN3601">12. References</a></h2>
<ul>
<li>
<p><a class="lk" href="https://tools.ietf.org/html/draft-grant-tacacs-02" target="_top">draft-grant-tacacs-02.txt - The TACACS+ Protocol (Version 1.78)</a></p>
</li>
<li>
<p><a class="lk" href="https://tools.ietf.org/html/rfc8907" target="_top">RFC8907: The Terminal Access Controller Access-Control System Plus (TACACS+) Protocol</a></p>
</li>
</ul>
</div>
<div class="section">
<hr>
<h2 class="section"><a name="AEN3611" id="AEN3611">13. Copyrights and Acknowledgements</a></h2>
<p>Please see the source for copyright and licensing information of individual files.</p>
<ul>
<li>
<p><span class="bold"><b class="emphasis">The following applies if the software was compiled with OpenSSL support:</b></span></p>
<p>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (<a class="lk" href="http://www.openssl.org/" target="_top">http://www.openssl.org/</a>).</p>
<p>This product includes cryptographic software written by Eric Young (<code class="email">&lt;<a class="lk" href="mailto:eay@cryptsoft.com">eay@cryptsoft.com</a>&gt;</code>).</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">MD4 algorithm:</b></span></p>
<p>The software uses the RSA Data Security, Inc. MD4 Message-Digest Algorithm.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">MD5 algorithm:</b></span></p>
<p>The software uses the RSA Data Security, Inc. MD5 Message-Digest Algorithm.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">If the software was compiled with PCRE (Perl Compatible Regular Expressions) support, the following applies:</b></span></p>
<p>Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. (<a class="lk" href="ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/" target="_top">ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/</a>).</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">The original tac_plus code (which this software and considerable parts of the documentation are based on) is distributed under the following license:</b></span></p>
<p>Copyright (c) 1995-1998 by Cisco systems, Inc.</p>
<p>Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that this copyright and permission notice appear on all copies of the software and supporting documentation, the name of Cisco Systems, Inc. not be used in advertising or publicity pertaining to distribution of the program without specific prior permission, and notice be given in supporting documentation that modification, copying and distribution is by permission of Cisco Systems, Inc.</p>
<p>Cisco Systems, Inc. makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.</p>
</li>
<li>
<p><span class="bold"><b class="emphasis">The code written by Marc Huber is distributed under the following license:</b></span></p>
<p>Copyright (C) 1999-2022 Marc Huber (<code class="email">&lt;<a class="lk" href="mailto:Marc.Huber@web.de">Marc.Huber@web.de</a>&gt;</code>). All rights reserved.</p>
<p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p>
<ol type="1">
<li>
<p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p>
</li>
<li>
<p>Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.</p>
</li>
<li>
<p>The end-user documentation included with the redistribution, if any, must include the following acknowledgment:</p>
<a name="AEN3654" id="AEN3654"></a>
<blockquote class="BLOCKQUOTE">
<p>This product includes software developed by Marc Huber (<code class="email">&lt;<a class="lk" href="mailto:Marc.Huber@web.de">Marc.Huber@web.de</a>&gt;</code>).</p>
</blockquote>
<p>Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear.</p>
</li>
</ol>
<p>THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITS AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>
</li>
</ul>
</div>
</div>
</body>
</html>
